Adding the reference builds as a DEPS rather than putting them in the main tree.


git-svn-id: http://src.chromium.org/svn/trunk/deps/reference_builds/chrome@25506 4ff67af0-8c30-449e-8e8b-ad334ec8d88c
diff --git a/First Run b/First Run
new file mode 100644
index 0000000..852ad16
--- /dev/null
+++ b/First Run
@@ -0,0 +1 @@
+krome 

diff --git a/chrome.dll b/chrome.dll
new file mode 100644
index 0000000..4ebaa46
--- /dev/null
+++ b/chrome.dll
Binary files differ
diff --git a/chrome.exe b/chrome.exe
new file mode 100644
index 0000000..8c20fc7
--- /dev/null
+++ b/chrome.exe
Binary files differ
diff --git a/chrome_dll.pdb b/chrome_dll.pdb
new file mode 100644
index 0000000..ef5ad39
--- /dev/null
+++ b/chrome_dll.pdb
Binary files differ
diff --git a/chrome_exe.pdb b/chrome_exe.pdb
new file mode 100644
index 0000000..4708dac
--- /dev/null
+++ b/chrome_exe.pdb
Binary files differ
diff --git a/crash_service.exe b/crash_service.exe
new file mode 100644
index 0000000..8f0d510
--- /dev/null
+++ b/crash_service.exe
Binary files differ
diff --git a/icudt38.dll b/icudt38.dll
new file mode 100644
index 0000000..8cbc57f
--- /dev/null
+++ b/icudt38.dll
Binary files differ
diff --git a/locales/ar.dll b/locales/ar.dll
new file mode 100644
index 0000000..8063823
--- /dev/null
+++ b/locales/ar.dll
Binary files differ
diff --git a/locales/bg.dll b/locales/bg.dll
new file mode 100644
index 0000000..4bfa803
--- /dev/null
+++ b/locales/bg.dll
Binary files differ
diff --git a/locales/ca.dll b/locales/ca.dll
new file mode 100644
index 0000000..b1bdaad
--- /dev/null
+++ b/locales/ca.dll
Binary files differ
diff --git a/locales/cs.dll b/locales/cs.dll
new file mode 100644
index 0000000..a2e69bd
--- /dev/null
+++ b/locales/cs.dll
Binary files differ
diff --git a/locales/da.dll b/locales/da.dll
new file mode 100644
index 0000000..1b6f0e7
--- /dev/null
+++ b/locales/da.dll
Binary files differ
diff --git a/locales/de.dll b/locales/de.dll
new file mode 100644
index 0000000..0de11d2
--- /dev/null
+++ b/locales/de.dll
Binary files differ
diff --git a/locales/el.dll b/locales/el.dll
new file mode 100644
index 0000000..94c2f02
--- /dev/null
+++ b/locales/el.dll
Binary files differ
diff --git a/locales/en-GB.dll b/locales/en-GB.dll
new file mode 100644
index 0000000..633cc4d
--- /dev/null
+++ b/locales/en-GB.dll
Binary files differ
diff --git a/locales/en-US.dll b/locales/en-US.dll
new file mode 100644
index 0000000..9687b08
--- /dev/null
+++ b/locales/en-US.dll
Binary files differ
diff --git a/locales/es-419.dll b/locales/es-419.dll
new file mode 100644
index 0000000..5408aee
--- /dev/null
+++ b/locales/es-419.dll
Binary files differ
diff --git a/locales/es.dll b/locales/es.dll
new file mode 100644
index 0000000..b239a54
--- /dev/null
+++ b/locales/es.dll
Binary files differ
diff --git a/locales/et.dll b/locales/et.dll
new file mode 100644
index 0000000..dd3230c
--- /dev/null
+++ b/locales/et.dll
Binary files differ
diff --git a/locales/fi.dll b/locales/fi.dll
new file mode 100644
index 0000000..8e56e69
--- /dev/null
+++ b/locales/fi.dll
Binary files differ
diff --git a/locales/fil.dll b/locales/fil.dll
new file mode 100644
index 0000000..584829b
--- /dev/null
+++ b/locales/fil.dll
Binary files differ
diff --git a/locales/fr.dll b/locales/fr.dll
new file mode 100644
index 0000000..6528d4a
--- /dev/null
+++ b/locales/fr.dll
Binary files differ
diff --git a/locales/he.dll b/locales/he.dll
new file mode 100644
index 0000000..8000e3b
--- /dev/null
+++ b/locales/he.dll
Binary files differ
diff --git a/locales/hi.dll b/locales/hi.dll
new file mode 100644
index 0000000..18d7de1
--- /dev/null
+++ b/locales/hi.dll
Binary files differ
diff --git a/locales/hr.dll b/locales/hr.dll
new file mode 100644
index 0000000..1ff7290
--- /dev/null
+++ b/locales/hr.dll
Binary files differ
diff --git a/locales/hu.dll b/locales/hu.dll
new file mode 100644
index 0000000..9e6aace
--- /dev/null
+++ b/locales/hu.dll
Binary files differ
diff --git a/locales/id.dll b/locales/id.dll
new file mode 100644
index 0000000..c81e508
--- /dev/null
+++ b/locales/id.dll
Binary files differ
diff --git a/locales/it.dll b/locales/it.dll
new file mode 100644
index 0000000..5d3c614
--- /dev/null
+++ b/locales/it.dll
Binary files differ
diff --git a/locales/ja.dll b/locales/ja.dll
new file mode 100644
index 0000000..9c0317c
--- /dev/null
+++ b/locales/ja.dll
Binary files differ
diff --git a/locales/ko.dll b/locales/ko.dll
new file mode 100644
index 0000000..acfe496
--- /dev/null
+++ b/locales/ko.dll
Binary files differ
diff --git a/locales/lt.dll b/locales/lt.dll
new file mode 100644
index 0000000..c3309cb
--- /dev/null
+++ b/locales/lt.dll
Binary files differ
diff --git a/locales/lv.dll b/locales/lv.dll
new file mode 100644
index 0000000..bd9d4ec
--- /dev/null
+++ b/locales/lv.dll
Binary files differ
diff --git a/locales/nb.dll b/locales/nb.dll
new file mode 100644
index 0000000..8ef7708
--- /dev/null
+++ b/locales/nb.dll
Binary files differ
diff --git a/locales/nl.dll b/locales/nl.dll
new file mode 100644
index 0000000..5280634
--- /dev/null
+++ b/locales/nl.dll
Binary files differ
diff --git a/locales/pl.dll b/locales/pl.dll
new file mode 100644
index 0000000..e968685
--- /dev/null
+++ b/locales/pl.dll
Binary files differ
diff --git a/locales/pt-BR.dll b/locales/pt-BR.dll
new file mode 100644
index 0000000..b1f8f2f
--- /dev/null
+++ b/locales/pt-BR.dll
Binary files differ
diff --git a/locales/pt-PT.dll b/locales/pt-PT.dll
new file mode 100644
index 0000000..2257373
--- /dev/null
+++ b/locales/pt-PT.dll
Binary files differ
diff --git a/locales/ro.dll b/locales/ro.dll
new file mode 100644
index 0000000..6f54163
--- /dev/null
+++ b/locales/ro.dll
Binary files differ
diff --git a/locales/ru.dll b/locales/ru.dll
new file mode 100644
index 0000000..fea12e3
--- /dev/null
+++ b/locales/ru.dll
Binary files differ
diff --git a/locales/sk.dll b/locales/sk.dll
new file mode 100644
index 0000000..abef9a8
--- /dev/null
+++ b/locales/sk.dll
Binary files differ
diff --git a/locales/sl.dll b/locales/sl.dll
new file mode 100644
index 0000000..ea4df1e
--- /dev/null
+++ b/locales/sl.dll
Binary files differ
diff --git a/locales/sr.dll b/locales/sr.dll
new file mode 100644
index 0000000..04f5a6f
--- /dev/null
+++ b/locales/sr.dll
Binary files differ
diff --git a/locales/sv.dll b/locales/sv.dll
new file mode 100644
index 0000000..b969966
--- /dev/null
+++ b/locales/sv.dll
Binary files differ
diff --git a/locales/th.dll b/locales/th.dll
new file mode 100644
index 0000000..fd0a335
--- /dev/null
+++ b/locales/th.dll
Binary files differ
diff --git a/locales/tr.dll b/locales/tr.dll
new file mode 100644
index 0000000..29336b2
--- /dev/null
+++ b/locales/tr.dll
Binary files differ
diff --git a/locales/uk.dll b/locales/uk.dll
new file mode 100644
index 0000000..224cb8c
--- /dev/null
+++ b/locales/uk.dll
Binary files differ
diff --git a/locales/vi.dll b/locales/vi.dll
new file mode 100644
index 0000000..04f7d21
--- /dev/null
+++ b/locales/vi.dll
Binary files differ
diff --git a/locales/zh-CN.dll b/locales/zh-CN.dll
new file mode 100644
index 0000000..9d37e3e
--- /dev/null
+++ b/locales/zh-CN.dll
Binary files differ
diff --git a/locales/zh-TW.dll b/locales/zh-TW.dll
new file mode 100644
index 0000000..c2322cc
--- /dev/null
+++ b/locales/zh-TW.dll
Binary files differ
diff --git a/plugins/gears/gears.dll b/plugins/gears/gears.dll
new file mode 100644
index 0000000..2e292b1
--- /dev/null
+++ b/plugins/gears/gears.dll
Binary files differ
diff --git a/resources/Inspector/BreakpointsSidebarPane.js b/resources/Inspector/BreakpointsSidebarPane.js
new file mode 100644
index 0000000..2b8f3cd
--- /dev/null
+++ b/resources/Inspector/BreakpointsSidebarPane.js
@@ -0,0 +1,85 @@
+/*
+ * 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.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)
+    {
+        this.breakpoints.push(breakpoint);
+        breakpoint.addEventListener("enabled", this._breakpointEnableChanged, this);
+        breakpoint.addEventListener("disabled", this._breakpointEnableChanged, this);
+
+        // FIXME: add to the breakpoints UI.
+
+        if (!InspectorController.debuggerEnabled() || !breakpoint.sourceID)
+            return;
+
+        if (breakpoint.enabled)
+            InspectorController.addBreakpoint(breakpoint.sourceID, breakpoint.line);
+    },
+
+    removeBreakpoint: function(breakpoint)
+    {
+        this.breakpoints.remove(breakpoint);
+        breakpoint.removeEventListener("enabled", null, this);
+        breakpoint.removeEventListener("disabled", null, this);
+
+        // FIXME: remove from the breakpoints UI.
+
+        if (!InspectorController.debuggerEnabled() || !breakpoint.sourceID)
+            return;
+
+        InspectorController.removeBreakpoint(breakpoint.sourceID, breakpoint.line);
+    },
+
+    _breakpointEnableChanged: function(event)
+    {
+        var breakpoint = event.target;
+
+        // FIXME: change the breakpoint checkbox state in the UI.
+
+        if (!InspectorController.debuggerEnabled() || !breakpoint.sourceID)
+            return;
+
+        if (breakpoint.enabled)
+            InspectorController.addBreakpoint(breakpoint.sourceID, breakpoint.line);
+        else
+            InspectorController.removeBreakpoint(breakpoint.sourceID, breakpoint.line);
+    }
+}
+
+WebInspector.BreakpointsSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype;
diff --git a/resources/Inspector/CallStackSidebarPane.js b/resources/Inspector/CallStackSidebarPane.js
new file mode 100644
index 0000000..a2c8bed
--- /dev/null
+++ b/resources/Inspector/CallStackSidebarPane.js
@@ -0,0 +1,110 @@
+/*
+ * 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"));
+}
+
+WebInspector.CallStackSidebarPane.prototype = {
+    update: function(callFrame, sourceIDMap)
+    {
+        this.bodyElement.removeChildren();
+
+        this.placards = [];
+        delete this._selectedCallFrame;
+
+        if (!callFrame) {
+            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;
+
+        do {
+            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);
+
+            callFrame = callFrame.caller;
+        } while (callFrame);
+    },
+
+    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");
+    },
+
+    _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/Console.js b/resources/Inspector/Console.js
new file mode 100644
index 0000000..c98d155
--- /dev/null
+++ b/resources/Inspector/Console.js
@@ -0,0 +1,948 @@
+/*
+ * 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.Console = function()
+{
+    this.messages = [];
+
+    WebInspector.View.call(this, document.getElementById("console"));
+
+    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), " .=:[({;");
+
+    this.toggleButton = document.getElementById("console-status-bar-item");
+    this.toggleButton.title = WebInspector.UIString("Show console.");
+    this.toggleButton.addEventListener("click", this._toggleButtonClicked.bind(this), false);
+
+    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.topGroup = new WebInspector.ConsoleGroup(null, 0);
+    this.messagesElement.insertBefore(this.topGroup.element, this.promptElement);
+    this.groupLevel = 0;
+    this.currentGroup = this.topGroup;
+
+    document.getElementById("main-status-bar").addEventListener("mousedown", this._startStatusBarDragging.bind(this), true);
+}
+
+WebInspector.Console.prototype = {
+    show: function()
+    {
+        if (this._animating || this.visible)
+            return;
+
+        WebInspector.View.prototype.show.call(this);
+
+        this._animating = true;
+
+        this.toggleButton.addStyleClass("toggled-on");
+        this.toggleButton.title = WebInspector.UIString("Hide console.");
+
+        document.body.addStyleClass("console-visible");
+
+        var anchoredItems = document.getElementById("anchored-status-bar-items");
+
+        var animations = [
+            {element: document.getElementById("main"), end: {bottom: this.element.offsetHeight}},
+            {element: document.getElementById("main-status-bar"), start: {"padding-left": anchoredItems.offsetWidth - 1}, end: {"padding-left": 0}},
+            {element: document.getElementById("other-console-status-bar-items"), start: {opacity: 0}, end: {opacity: 1}}
+        ];
+
+        var consoleStatusBar = document.getElementById("console-status-bar");
+        consoleStatusBar.insertBefore(anchoredItems, consoleStatusBar.firstChild);
+
+        function animationFinished()
+        {
+            if ("updateStatusBarItems" in WebInspector.currentPanel)
+                WebInspector.currentPanel.updateStatusBarItems();
+            WebInspector.currentFocusElement = this.promptElement;
+            delete this._animating;
+        }
+
+        WebInspector.animateStyle(animations, window.event && window.event.shiftKey ? 2000 : 250, animationFinished.bind(this));
+
+        if (!this.prompt.isCaretInsidePrompt())
+            this.prompt.moveCaretToEndOfPrompt();
+    },
+
+    hide: function()
+    {
+        if (this._animating || !this.visible)
+            return;
+
+        WebInspector.View.prototype.hide.call(this);
+
+        this._animating = true;
+
+        this.toggleButton.removeStyleClass("toggled-on");
+        this.toggleButton.title = WebInspector.UIString("Show console.");
+
+        if (this.element === WebInspector.currentFocusElement || this.element.isAncestor(WebInspector.currentFocusElement))
+            WebInspector.currentFocusElement = WebInspector.previousFocusElement;
+
+        var anchoredItems = document.getElementById("anchored-status-bar-items");
+
+        // Temporally set properties and classes to mimic the post-animation values so panels
+        // like Elements in their updateStatusBarItems call will size things to fit the final location.
+        document.getElementById("main-status-bar").style.setProperty("padding-left", (anchoredItems.offsetWidth - 1) + "px");
+        document.body.removeStyleClass("console-visible");
+        if ("updateStatusBarItems" in WebInspector.currentPanel)
+            WebInspector.currentPanel.updateStatusBarItems();
+        document.body.addStyleClass("console-visible");
+
+        var animations = [
+            {element: document.getElementById("main"), end: {bottom: 0}},
+            {element: document.getElementById("main-status-bar"), start: {"padding-left": 0}, end: {"padding-left": anchoredItems.offsetWidth - 1}},
+            {element: document.getElementById("other-console-status-bar-items"), start: {opacity: 1}, end: {opacity: 0}}
+        ];
+
+        function animationFinished()
+        {
+            var mainStatusBar = document.getElementById("main-status-bar");
+            mainStatusBar.insertBefore(anchoredItems, mainStatusBar.firstChild);
+            mainStatusBar.style.removeProperty("padding-left");
+            document.body.removeStyleClass("console-visible");
+            delete this._animating;
+        }
+
+        WebInspector.animateStyle(animations, window.event && window.event.shiftKey ? 2000 : 250, animationFinished.bind(this));
+    },
+
+    addMessage: function(msg)
+    {
+        if (msg instanceof WebInspector.ConsoleMessage) {
+            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.level === WebInspector.ConsoleMessage.MessageLevel.EndGroup) {
+            if (this.groupLevel < 1)
+                return;
+
+            this.groupLevel--;
+
+            this.currentGroup = this.currentGroup.parentGroup;
+        } else {
+            if (msg.level === WebInspector.ConsoleMessage.MessageLevel.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();
+        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)
+    {
+        // Pass less stop characters to rangeOfWord so the range will be a more complete expression.
+        const expressionStopCharacters = " =:{;";
+        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 result;
+        if (expressionString) {
+            try {
+                result = this._evalInInspectedWindow(expressionString);
+            } catch(e) {
+                // Do nothing, the prefix will be considered a window property.
+            }
+        } else {
+            // There is no expressionString, so the completion should happen against global properties.
+            // Or if the debugger is paused, against properties in scope of the selected call frame.
+            if (WebInspector.panels.scripts && WebInspector.panels.scripts.paused)
+                result = WebInspector.panels.scripts.variablesInScopeForSelectedCallFrame();
+            else
+                result = InspectorController.inspectedWindow();
+        }
+
+        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;
+        }
+
+        return results;
+    },
+
+    _toggleButtonClicked: function()
+    {
+        this.visible = !this.visible;
+    },
+
+    _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);
+        event.stopPropagation();
+        event.preventDefault();
+    },
+
+    _promptKeyDown: function(event)
+    {
+        switch (event.keyIdentifier) {
+            case "Enter":
+                this._enterKeyPressed(event);
+                return;
+        }
+
+        this.prompt.handleKeyEvent(event);
+    },
+
+    _startStatusBarDragging: function(event)
+    {
+        if (!this.visible || event.target !== document.getElementById("main-status-bar"))
+            return;
+
+        WebInspector.elementDragStart(document.getElementById("main-status-bar"), this._statusBarDragging.bind(this), this._endStatusBarDragging.bind(this), event, "row-resize");
+
+        this._statusBarDragOffset = event.pageY - this.element.totalOffsetTop;
+
+        event.stopPropagation();
+    },
+
+    _statusBarDragging: function(event)
+    {
+        var mainElement = document.getElementById("main");
+
+        var height = window.innerHeight - event.pageY + this._statusBarDragOffset;
+        height = Number.constrain(height, Preferences.minConsoleHeight, window.innerHeight - mainElement.totalOffsetTop - Preferences.minConsoleHeight);
+
+        mainElement.style.bottom = height + "px";
+        this.element.style.height = height + "px";
+
+        event.preventDefault();
+        event.stopPropagation();
+    },
+
+    _endStatusBarDragging: function(event)
+    {
+        WebInspector.elementDragEnd(event);
+
+        delete this._statusBarDragOffset;
+
+        event.stopPropagation();
+    },
+
+    _evalInInspectedWindow: function(expression)
+    {
+        if (WebInspector.panels.scripts && WebInspector.panels.scripts.paused)
+            return WebInspector.panels.scripts.evaluateInSelectedCallFrame(expression);
+        var inspectedWindow = InspectorController.inspectedWindow();
+        if (!inspectedWindow._inspectorCommandLineAPI) {
+            inspectedWindow.eval("window._inspectorCommandLineAPI = { \
+                $: function() { return document.getElementById.apply(document, arguments) }, \
+                $$: function() { return document.querySelectorAll.apply(document, arguments) }, \
+                $x: function(xpath, context) { \
+                    var nodes = []; \
+                    try { \
+                        var doc = context || document; \
+                        var results = doc.evaluate(xpath, doc, null, XPathResult.ANY_TYPE, null); \
+                        var node; \
+                        while (node = results.iterateNext()) nodes.push(node); \
+                    } catch (e) {} \
+                    return nodes; \
+                }, \
+                dir: function() { return console.dir.apply(console, arguments) }, \
+                dirxml: function() { return console.dirxml.apply(console, arguments) }, \
+                keys: function(o) { var a = []; for (k in o) a.push(k); return a; }, \
+                values: function(o) { var a = []; for (k in o) a.push(o[k]); return a; }, \
+                profile: function() { return console.profile.apply(console, arguments) }, \
+                profileEnd: function() { return console.profileEnd.apply(console, arguments) } \
+            };");
+
+            inspectedWindow._inspectorCommandLineAPI.clear = InspectorController.wrapCallback(this.clearMessages.bind(this));
+        }
+
+        // Surround the expression in with statements to inject our command line API so that
+        // the window object properties still take more precedent than our API functions.
+        expression = "with (window._inspectorCommandLineAPI) { with (window) { " + expression + " } }";
+
+        return inspectedWindow.eval(expression);
+    },
+
+    _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 result;
+        var exception = false;
+        try {
+            result = this._evalInInspectedWindow(str);
+        } catch(e) {
+            result = e;
+            exception = true;
+        }
+
+        this.prompt.history.push(str);
+        this.prompt.historyOffset = 0;
+        this.prompt.text = "";
+
+        var level = exception ? WebInspector.ConsoleMessage.MessageLevel.Error : WebInspector.ConsoleMessage.MessageLevel.Log;
+        this.addMessage(new WebInspector.ConsoleCommand(str, result, this._format(result), level));
+    },
+
+    _mouseOverNode: function(event)
+    {
+        var anchorElement = event.target.enclosingNodeOrSelfWithNodeName("a");
+        WebInspector.hoveredDOMNode = (anchorElement ? anchorElement.representedNode : null);
+    },
+
+    _mouseOutOfNode: function(event)
+    {
+        var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY);
+        var anchorElement = nodeUnderMouse.enclosingNodeOrSelfWithNodeName("a");
+        if (!anchorElement || !anchorElement.representedNode)
+            WebInspector.hoveredDOMNode = null;
+    },
+
+    _format: function(output, inline)
+    {
+        var type = Object.type(output, InspectorController.inspectedWindow());
+        if (type === "object") {
+            if (output instanceof InspectorController.inspectedWindow().Node)
+                type = "node";
+        }
+
+        // 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,
+            "date": 1,
+            "function": 1,
+        };
+
+        var formatter;
+        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, inline);
+        return span;
+    },
+
+    _formatvalue: function(val, elem, inline)
+    {
+        elem.appendChild(document.createTextNode(val));
+    },
+
+    _formatstring: function(str, elem, inline)
+    {
+        elem.appendChild(document.createTextNode("\"" + str + "\""));
+    },
+
+    _formatregexp: function(re, elem, inline)
+    {
+        var formatted = String(re).replace(/([\\\/])/g, "\\$1").replace(/\\(\/[gim]*)$/, "$1").substring(1);
+        elem.appendChild(document.createTextNode(formatted));
+    },
+
+    _formatarray: function(arr, elem, inline)
+    {
+        elem.appendChild(document.createTextNode("["));
+        for (var i = 0; i < arr.length; ++i) {
+            elem.appendChild(this._format(arr[i], true));
+            if (i < arr.length - 1)
+                elem.appendChild(document.createTextNode(", "));
+        }
+        elem.appendChild(document.createTextNode("]"));
+    },
+
+    _formatnode: function(node, elem, inline)
+    {
+        var anchor = document.createElement("a");
+        anchor.className = "inspectible-node";
+        anchor.innerHTML = nodeTitleInfo.call(node).title;
+        anchor.representedNode = node;
+        anchor.addEventListener("mouseover", this._mouseOverNode.bind(this), false);
+        anchor.addEventListener("mouseout", this._mouseOutOfNode.bind(this), false);
+
+        if (inline)
+            elem.appendChild(anchor);
+        else
+            elem.appendChild(new WebInspector.ObjectPropertiesSection(node, anchor, null, null, true).element);
+    },
+
+    _formatobject: function(obj, elem, inline)
+    {
+        if (inline)
+            elem.appendChild(document.createTextNode(Object.describe(obj)));
+        else
+            elem.appendChild(new WebInspector.ObjectPropertiesSection(obj, null, null, null, true).element);
+    },
+
+    _formaterror: function(obj, elem, inline)
+    {
+        elem.appendChild(document.createTextNode(obj.name + ": " + obj.message + " "));
+
+        if (obj.sourceURL) {
+            var urlElement = document.createElement("a");
+            urlElement.className = "console-message-url webkit-html-resource-link";
+            urlElement.href = obj.sourceURL;
+            urlElement.lineNumber = obj.line;
+            urlElement.preferredPanel = "scripts";
+
+            if (obj.line > 0)
+                urlElement.textContent = WebInspector.UIString("%s (line %d)", obj.sourceURL, obj.line);
+            else
+                urlElement.textContent = obj.sourceURL;
+
+            elem.appendChild(urlElement);
+        }
+    },
+}
+
+WebInspector.Console.prototype.__proto__ = WebInspector.View.prototype;
+
+WebInspector.ConsoleMessage = function(source, level, line, url, groupLevel, repeatCount)
+{
+    this.source = source;
+    this.level = level;
+    this.line = line;
+    this.url = url;
+    this.groupLevel = groupLevel;
+    this.repeatCount = repeatCount;
+
+    switch (this.level) {
+        case WebInspector.ConsoleMessage.MessageLevel.Object:
+            var propertiesSection = new WebInspector.ObjectPropertiesSection(arguments[6], null, null, null, true);
+            propertiesSection.element.addStyleClass("console-message");
+            this.propertiesSection = propertiesSection;
+            break;
+        case WebInspector.ConsoleMessage.MessageLevel.Node:
+            var node = arguments[6];
+            if (!(node instanceof InspectorController.inspectedWindow().Node))
+                return;
+            this.elementsTreeOutline = new WebInspector.ElementsTreeOutline();
+            this.elementsTreeOutline.rootDOMNode = node;
+            break;
+        case WebInspector.ConsoleMessage.MessageLevel.Trace:
+            var span = document.createElement("span");
+            span.addStyleClass("console-formatted-trace");
+            var stack = Array.prototype.slice.call(arguments, 6);
+            var funcNames = stack.map(function(f) {
+                return f || WebInspector.UIString("(anonymous function)");
+            });
+            span.appendChild(document.createTextNode(funcNames.join("\n")));
+            this.formattedMessage = span;
+            break;
+        default:
+            // The formatedMessage property is used for the rich and interactive console.
+            this.formattedMessage = this._format(Array.prototype.slice.call(arguments, 6));
+
+            // This is used for inline message bubbles in SourceFrames, or other plain-text representations.
+            this.message = this.formattedMessage.textContent;
+            break;
+    }
+}
+
+WebInspector.ConsoleMessage.prototype = {
+    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;
+
+        function formatForConsole(obj)
+        {
+            return WebInspector.console._format(obj, true);
+        }
+
+        if (Object.type(parameters[0], InspectorController.inspectedWindow()) === "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;
+
+            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], 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 (typeof parameters[i] === "string")
+                formattedResult.appendChild(WebInspector.linkifyStringAsFragment(parameters[i]));
+            else if (parameters.length === 1)
+                formattedResult.appendChild(WebInspector.console._format(parameters[0]));
+            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.Warning:
+                element.addStyleClass("console-warning-level");
+                break;
+            case WebInspector.ConsoleMessage.MessageLevel.Error:
+                element.addStyleClass("console-error-level");
+                break;
+            case WebInspector.ConsoleMessage.MessageLevel.StartGroup:
+                element.addStyleClass("console-group-title-level");
+        }
+
+        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.UIString("%s (line %d)", 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 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.Error:
+                levelString = "Error";
+                break;
+            case WebInspector.ConsoleMessage.MessageLevel.Object:
+                levelString = "Object";
+                break;
+            case WebInspector.ConsoleMessage.MessageLevel.GroupTitle:
+                levelString = "GroupTitle";
+                break;
+        }
+
+        return sourceString + " " + 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.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.MessageLevel = {
+    Tip: 0,
+    Log: 1,
+    Warning: 2,
+    Error: 3,
+    Object: 4,
+    Node: 5,
+    Trace: 6,
+    StartGroup: 7,
+    EndGroup: 8
+}
+
+WebInspector.ConsoleCommand = function(command, result, formattedResultElement, level)
+{
+    this.command = command;
+    this.formattedResultElement = formattedResultElement;
+    this.level = level;
+}
+
+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);
+
+        var resultElement = document.createElement("div");
+        resultElement.className = "console-message";
+        element.appendChild(resultElement);
+
+        switch (this.level) {
+            case WebInspector.ConsoleMessage.MessageLevel.Log:
+                resultElement.addStyleClass("console-log-level");
+                break;
+            case WebInspector.ConsoleMessage.MessageLevel.Warning:
+                resultElement.addStyleClass("console-warning-level");
+                break;
+            case WebInspector.ConsoleMessage.MessageLevel.Error:
+                resultElement.addStyleClass("console-error-level");
+        }
+
+        var resultTextElement = document.createElement("span");
+        resultTextElement.className = "console-message-text";
+        resultTextElement.appendChild(this.formattedResultElement);
+        resultElement.appendChild(resultTextElement);
+
+        return element;
+    }
+}
+
+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.level === WebInspector.ConsoleMessage.MessageLevel.StartGroup) {
+            this.messagesElement.parentNode.insertBefore(element, this.messagesElement);
+            element.addEventListener("click", this._titleClicked.bind(this), true);
+        } else
+            this.messagesElement.appendChild(element);
+    },
+    
+    _titleClicked: function(event)
+    {
+        var groupTitleElement = event.target.enclosingNodeOrSelfWithClass("console-group-title-level");
+        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/Database.js b/resources/Inspector/Database.js
new file mode 100644
index 0000000..ef42e15
--- /dev/null
+++ b/resources/Inspector/Database.js
@@ -0,0 +1,95 @@
+/*
+ * 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(database, domain, name, version)
+{
+    this.database = database;
+    this.domain = domain;
+    this.name = name;
+    this.version = version;
+}
+
+WebInspector.Database.prototype = {
+    get database()
+    {
+        return this._database;
+    },
+
+    set database(x)
+    {
+        if (this._database === x)
+            return;
+        this._database = x;
+    },
+
+    get name()
+    {
+        return this._name;
+    },
+
+    set name(x)
+    {
+        if (this._name === x)
+            return;
+        this._name = x;
+    },
+
+    get version()
+    {
+        return this._version;
+    },
+
+    set version(x)
+    {
+        if (this._version === x)
+            return;
+        this._version = x;
+    },
+
+    get domain()
+    {
+        return this._domain;
+    },
+
+    set domain(x)
+    {
+        if (this._domain === x)
+            return;
+        this._domain = x;
+    },
+
+    get displayDomain()
+    {
+        return WebInspector.Resource.prototype.__lookupGetter__("displayDomain").call(this);
+    },
+
+    get tableNames()
+    {
+        return InspectorController.databaseTableNames(this.database).sort();
+    }
+}
diff --git a/resources/Inspector/DatabaseQueryView.js b/resources/Inspector/DatabaseQueryView.js
new file mode 100644
index 0000000..122707f
--- /dev/null
+++ b/resources/Inspector/DatabaseQueryView.js
@@ -0,0 +1,199 @@
+/*
+ * 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)
+    {
+        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;
+            }
+        }
+
+        accumulateMatches(this.database.tableNames.map(function(name) { return name + " " }));
+        accumulateMatches(["SELECT ", "FROM ", "WHERE ", "LIMIT ", "DELETE FROM ", "CREATE ", "DROP ", "TABLE ", "INDEX ", "UPDATE ", "INSERT INTO ", "VALUES ("]);
+
+        return results;
+    },
+
+    _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 = "";
+
+        function queryTransaction(tx)
+        {
+            tx.executeSql(query, null, InspectorController.wrapCallback(this._queryFinished.bind(this, query)), InspectorController.wrapCallback(this._executeSqlError.bind(this, query)));
+        }
+
+        this.database.database.transaction(InspectorController.wrapCallback(queryTransaction.bind(this)), InspectorController.wrapCallback(this._queryError.bind(this, query)));
+    },
+
+    _queryFinished: function(query, tx, result)
+    {
+        var dataGrid = WebInspector.panels.databases.dataGridForResult(result);
+        dataGrid.element.addStyleClass("inline");
+        this._appendQueryResult(query, dataGrid.element);
+
+        if (query.match(/^create /i) || query.match(/^drop table /i))
+            WebInspector.panels.databases.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 occured.", error.code);
+
+        this._appendQueryResult(query, message, "error");
+    },
+
+    _executeSqlError: function(query, tx, error)
+    {
+        this._queryError(query, 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
new file mode 100644
index 0000000..5d2bb88
--- /dev/null
+++ b/resources/Inspector/DatabaseTableView.js
@@ -0,0 +1,82 @@
+/*
+ * 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");
+}
+
+WebInspector.DatabaseTableView.prototype = {
+    show: function(parentElement)
+    {
+        WebInspector.View.prototype.show.call(this, parentElement);
+        this.update();
+    },
+
+    update: function()
+    {
+        function queryTransaction(tx)
+        {
+            tx.executeSql("SELECT * FROM " + this.tableName, null, InspectorController.wrapCallback(this._queryFinished.bind(this)), InspectorController.wrapCallback(this._queryError.bind(this)));
+        }
+
+        this.database.database.transaction(InspectorController.wrapCallback(queryTransaction.bind(this)), InspectorController.wrapCallback(this._queryError.bind(this)));
+    },
+
+    _queryFinished: function(tx, result)
+    {
+        this.element.removeChildren();
+
+        var dataGrid = WebInspector.panels.databases.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(tx, 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);
+    },
+
+}
+
+WebInspector.DatabaseTableView.prototype.__proto__ = WebInspector.View.prototype;
diff --git a/resources/Inspector/DatabasesPanel.js b/resources/Inspector/DatabasesPanel.js
new file mode 100644
index 0000000..bafa54a
--- /dev/null
+++ b/resources/Inspector/DatabasesPanel.js
@@ -0,0 +1,504 @@
+/*
+ * 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.DatabasesPanel = function(database)
+{
+    WebInspector.Panel.call(this);
+
+    this.sidebarElement = document.createElement("div");
+    this.sidebarElement.id = "databases-sidebar";
+    this.sidebarElement.className = "sidebar";
+    this.element.appendChild(this.sidebarElement);
+
+    this.sidebarResizeElement = document.createElement("div");
+    this.sidebarResizeElement.className = "sidebar-resizer-vertical";
+    this.sidebarResizeElement.addEventListener("mousedown", this._startSidebarDragging.bind(this), false);
+    this.element.appendChild(this.sidebarResizeElement);
+
+    this.sidebarTreeElement = document.createElement("ol");
+    this.sidebarTreeElement.className = "sidebar-tree";
+    this.sidebarElement.appendChild(this.sidebarTreeElement);
+
+    this.sidebarTree = new TreeOutline(this.sidebarTreeElement);
+
+    this.databasesListTreeElement = new WebInspector.SidebarSectionTreeElement(WebInspector.UIString("DATABASES"), {}, true);
+    this.sidebarTree.appendChild(this.databasesListTreeElement);
+    this.databasesListTreeElement.expand();
+
+    this.localStorageListTreeElement = new WebInspector.SidebarSectionTreeElement(WebInspector.UIString("LOCAL STORAGE"), {}, true);
+    this.sidebarTree.appendChild(this.localStorageListTreeElement);
+    this.localStorageListTreeElement.expand();
+
+    this.sessionStorageListTreeElement = new WebInspector.SidebarSectionTreeElement(WebInspector.UIString("SESSION STORAGE"), {}, true);
+    this.sidebarTree.appendChild(this.sessionStorageListTreeElement);
+    this.sessionStorageListTreeElement.expand();
+
+    this.storageViews = document.createElement("div");
+    this.storageViews.id = "storage-views";
+    this.element.appendChild(this.storageViews);
+
+    this.reset();
+}
+
+WebInspector.DatabasesPanel.prototype = {
+    toolbarItemClass: "databases",
+
+    get toolbarItemLabel()
+    {
+        return WebInspector.UIString("Databases");
+    },
+
+    show: function()
+    {
+        WebInspector.Panel.prototype.show.call(this);
+        this._updateSidebarWidth();
+    },
+
+    reset: function()
+    {
+        if (this._databases) {
+            var databasesLength = this._databases.length;
+            for (var i = 0; i < databasesLength; ++i) {
+                var database = this._databases[i];
+
+                delete database._tableViews;
+                delete database._queryView;
+            }
+        }
+
+        this._databases = [];
+
+        if (this._domStorage) {
+            var domStorageLength = this._domStorage.length;
+            for (var i = 0; i < domStorageLength; ++i) {
+                var domStorage = this._domStorage[i];
+
+                delete domStorage._domStorageView;
+            }
+        }
+
+        this._domStorage = [];
+
+        this.databasesListTreeElement.removeChildren();
+        this.localStorageListTreeElement.removeChildren();
+        this.sessionStorageListTreeElement.removeChildren();
+        this.storageViews.removeChildren();
+    },
+
+    handleKeyEvent: function(event)
+    {
+        this.sidebarTree.handleKeyEvent(event);
+    },
+
+    addDatabase: function(database)
+    {
+        this._databases.push(database);
+
+        var databaseTreeElement = new WebInspector.DatabaseSidebarTreeElement(database);
+        database._databasesTreeElement = databaseTreeElement;
+        this.databasesListTreeElement.appendChild(databaseTreeElement);
+    },
+
+    addDOMStorage: function(domStorage)
+    {
+        this._domStorage.push(domStorage);
+        var domStorageTreeElement = new WebInspector.DOMStorageSidebarTreeElement(domStorage);
+        domStorage._domStorageTreeElement = domStorageTreeElement;
+        if (domStorage.isLocalStorage)
+            this.localStorageListTreeElement.appendChild(domStorageTreeElement);
+        else
+            this.sessionStorageListTreeElement.appendChild(domStorageTreeElement);
+    },
+
+    showDatabase: function(database, tableName)
+    {
+        if (!database)
+            return;
+
+        if (this.visibleView)
+            this.visibleView.hide();
+
+        var view;
+        if (tableName) {
+            if (!("_tableViews" in database))
+                database._tableViews = {};
+            view = database._tableViews[tableName];
+            if (!view) {
+                view = new WebInspector.DatabaseTableView(database, tableName);
+                database._tableViews[tableName] = view;
+            }
+        } else {
+            view = database._queryView;
+            if (!view) {
+                view = new WebInspector.DatabaseQueryView(database);
+                database._queryView = view;
+            }
+        }
+
+        view.show(this.storageViews);
+
+        this.visibleView = view;
+    },
+
+    showDOMStorage: function(domStorage)
+    {
+        if (!domStorage)
+            return;
+
+        if (this.visibleView)
+            this.visibleView.hide();
+
+        var view;
+        view = domStorage._domStorageView;
+        if (!view) {
+            view = new WebInspector.DOMStorageItemsView(domStorage);
+            domStorage._domStorageView = view;
+        }
+
+        view.show(this.storageViews);
+
+        this.visibleView = view;
+    },
+
+    closeVisibleView: function()
+    {
+        if (this.visibleView)
+            this.visibleView.hide();
+        delete this.visibleView;
+    },
+
+    updateDatabaseTables: function(database)
+    {
+        if (!database || !database._databasesTreeElement)
+            return;
+
+        database._databasesTreeElement.shouldRefreshChildren = true;
+
+        if (!("_tableViews" in database))
+            return;
+
+        var tableNamesHash = {};
+        var tableNames = database.tableNames;
+        var tableNamesLength = tableNames.length;
+        for (var i = 0; i < tableNamesLength; ++i)
+            tableNamesHash[tableNames[i]] = true;
+
+        for (var tableName in database._tableViews) {
+            if (!(tableName in tableNamesHash)) {
+                if (this.visibleView === database._tableViews[tableName])
+                    this.closeVisibleView();
+                delete database._tableViews[tableName];
+            }
+        }
+    },
+
+    dataGridForResult: function(result)
+    {
+        if (!result.rows.length)
+            return null;
+
+        var columns = {};
+
+        var rows = result.rows;
+        for (var columnIdentifier in rows.item(0)) {
+            var column = {};
+            column.width = columnIdentifier.length;
+            column.title = columnIdentifier;
+
+            columns[columnIdentifier] = column;
+        }
+
+        var nodes = [];
+        var length = rows.length;
+        for (var i = 0; i < length; ++i) {
+            var data = {};
+
+            var row = rows.item(i);
+            for (var columnIdentifier in row) {
+                // FIXME: (Bug 19439) We should specially format SQL NULL here
+                // (which is represented by JavaScript null here, and turned
+                // into the string "null" by the String() function).
+                var text = String(row[columnIdentifier]);
+                data[columnIdentifier] = text;
+                if (text.length > columns[columnIdentifier].width)
+                    columns[columnIdentifier].width = text.length;
+            }
+
+            var node = new WebInspector.DataGridNode(data, false);
+            node.selectable = false;
+            nodes.push(node);
+        }
+
+        var totalColumnWidths = 0;
+        for (var columnIdentifier in columns)
+            totalColumnWidths += columns[columnIdentifier].width;
+
+        // Calculate the percentage width for the columns.
+        const minimumPrecent = 5;
+        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.
+        while (recoupPercent > 0) {
+            for (var columnIdentifier in columns) {
+                if (columns[columnIdentifier].width > minimumPrecent) {
+                    --columns[columnIdentifier].width;
+                    --recoupPercent;
+                    if (!recoupPercent)
+                        break;
+                }
+            }
+        }
+
+        // Change the width property to a string suitable for a style width.
+        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]);
+
+        return dataGrid;
+    },
+
+    dataGridForDOMStorage: function(domStorage)
+    {
+        if (!domStorage.length)
+            return null;
+
+        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[0].title.length;
+
+        var nodes = [];
+        
+        var length = domStorage.length;
+        for (index = 0; index < domStorage.length; index++) {
+            var data = {};
+       
+            var key = String(domStorage.key(index));
+            data[0] = key;
+            if (key.length > columns[0].width)
+                columns[0].width = key.length;
+        
+            var value = String(domStorage.getItem(key));
+            data[1] = value;
+            if (value.length > columns[1].width)
+                columns[1].width = value.length;
+            var node = new WebInspector.DataGridNode(data, false);
+            node.selectable = false;
+            nodes.push(node);
+        }
+
+        var totalColumnWidths = columns[0].width + columns[1].width;
+        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.DataGrid(columns);
+        var length = nodes.length;
+        for (var i = 0; i < length; ++i)
+            dataGrid.appendChild(nodes[i]);
+
+        return dataGrid;
+    },
+
+    _startSidebarDragging: function(event)
+    {
+        WebInspector.elementDragStart(this.sidebarResizeElement, this._sidebarDragging.bind(this), this._endSidebarDragging.bind(this), event, "col-resize");
+    },
+
+    _sidebarDragging: function(event)
+    {
+        this._updateSidebarWidth(event.pageX);
+
+        event.preventDefault();
+    },
+
+    _endSidebarDragging: function(event)
+    {
+        WebInspector.elementDragEnd(event);
+    },
+
+    _updateSidebarWidth: function(width)
+    {
+        if (this.sidebarElement.offsetWidth <= 0) {
+            // The stylesheet hasn't loaded yet or the window is closed,
+            // so we can't calculate what is need. Return early.
+            return;
+        }
+
+        if (!("_currentSidebarWidth" in this))
+            this._currentSidebarWidth = this.sidebarElement.offsetWidth;
+
+        if (typeof width === "undefined")
+            width = this._currentSidebarWidth;
+
+        width = Number.constrain(width, Preferences.minSidebarWidth, window.innerWidth / 2);
+
+        this._currentSidebarWidth = width;
+
+        this.sidebarElement.style.width = width + "px";
+        this.storageViews.style.left = width + "px";
+        this.sidebarResizeElement.style.left = (width - 3) + "px";
+    }
+}
+
+WebInspector.DatabasesPanel.prototype.__proto__ = WebInspector.Panel.prototype;
+
+WebInspector.DatabaseSidebarTreeElement = function(database)
+{
+    this.database = database;
+
+    WebInspector.SidebarTreeElement.call(this, "database-sidebar-tree-item", "", "", database, true);
+
+    this.refreshTitles();
+}
+
+WebInspector.DatabaseSidebarTreeElement.prototype = {
+    onselect: function()
+    {
+        WebInspector.panels.databases.showDatabase(this.database);
+    },
+
+    oncollapse: function()
+    {
+        // Request a refresh after every collapse so the next
+        // expand will have an updated table list.
+        this.shouldRefreshChildren = true;
+    },
+
+    onpopulate: function()
+    {
+        this.removeChildren();
+
+        var tableNames = this.database.tableNames;
+        var tableNamesLength = tableNames.length;
+        for (var i = 0; i < tableNamesLength; ++i)
+            this.appendChild(new WebInspector.SidebarDatabaseTableTreeElement(this.database, tableNames[i]));
+    },
+
+    get mainTitle()
+    {
+        return this.database.name;
+    },
+
+    set mainTitle(x)
+    {
+        // Do nothing.
+    },
+
+    get subtitle()
+    {
+        return this.database.displayDomain;
+    },
+
+    set subtitle(x)
+    {
+        // Do nothing.
+    }
+}
+
+WebInspector.DatabaseSidebarTreeElement.prototype.__proto__ = WebInspector.SidebarTreeElement.prototype;
+
+WebInspector.SidebarDatabaseTableTreeElement = function(database, tableName)
+{
+    this.database = database;
+    this.tableName = tableName;
+
+    WebInspector.SidebarTreeElement.call(this, "database-table-sidebar-tree-item small", tableName, "", null, false);
+}
+
+WebInspector.SidebarDatabaseTableTreeElement.prototype = {
+    onselect: function()
+    {
+        WebInspector.panels.databases.showDatabase(this.database, this.tableName);
+    }
+}
+
+WebInspector.SidebarDatabaseTableTreeElement.prototype.__proto__ = WebInspector.SidebarTreeElement.prototype;
+
+WebInspector.DOMStorageSidebarTreeElement = function(domStorage)
+{
+
+    this.domStorage = domStorage;
+
+    WebInspector.SidebarTreeElement.call(this, "domstorage-sidebar-tree-item", domStorage, "", null, false);
+
+    this.refreshTitles();
+}
+
+WebInspector.DOMStorageSidebarTreeElement.prototype = {
+    onselect: function()
+    {
+        WebInspector.panels.databases.showDOMStorage(this.domStorage);
+    },
+
+    get mainTitle()
+    {
+        return this.domStorage.domain;
+    },
+
+    set mainTitle(x)
+    {
+        // Do nothing.
+    },
+
+    get subtitle()
+    {
+        return ""; //this.database.displayDomain;
+    },
+
+    set subtitle(x)
+    {
+        // Do nothing.
+    }
+}
+
+WebInspector.DOMStorageSidebarTreeElement.prototype.__proto__ = WebInspector.SidebarTreeElement.prototype;
diff --git a/resources/Inspector/ElementsPanel.js b/resources/Inspector/ElementsPanel.js
new file mode 100644
index 0000000..3c9be54
--- /dev/null
+++ b/resources/Inspector/ElementsPanel.js
@@ -0,0 +1,1206 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc.  All rights reserved.
+ * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
+ *
+ * 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.ElementsPanel = function()
+{
+    WebInspector.Panel.call(this);
+
+    this.element.addStyleClass("elements");
+
+    this.contentElement = document.createElement("div");
+    this.contentElement.id = "elements-content";
+    this.contentElement.className = "outline-disclosure";
+
+    this.treeOutline = new WebInspector.ElementsTreeOutline();
+    this.treeOutline.panel = this;
+    this.treeOutline.includeRootDOMNode = false;
+    this.treeOutline.selectEnabled = true;
+
+    this.treeOutline.focusedNodeChanged = function(forceUpdate)
+    {
+        if (this.panel.visible && WebInspector.currentFocusElement !== document.getElementById("search"))
+            WebInspector.currentFocusElement = document.getElementById("main-panels");
+
+        this.panel.updateBreadcrumb(forceUpdate);
+
+        for (var pane in this.panel.sidebarPanes)
+           this.panel.sidebarPanes[pane].needsUpdate = true;
+
+        this.panel.updateStyles(true);
+        this.panel.updateMetrics();
+        this.panel.updateProperties();
+
+        if (InspectorController.searchingForNode()) {
+            InspectorController.toggleNodeSearch();
+            this.panel.nodeSearchButton.removeStyleClass("toggled-on");
+        }
+    };
+
+    this.contentElement.appendChild(this.treeOutline.element);
+
+    this.crumbsElement = document.createElement("div");
+    this.crumbsElement.className = "crumbs";
+    this.crumbsElement.addEventListener("mousemove", this._mouseMovedInCrumbs.bind(this), false);
+    this.crumbsElement.addEventListener("mouseout", this._mouseMovedOutOfCrumbs.bind(this), false);
+
+    this.sidebarPanes = {};
+    this.sidebarPanes.styles = new WebInspector.StylesSidebarPane();
+    this.sidebarPanes.metrics = new WebInspector.MetricsSidebarPane();
+    this.sidebarPanes.properties = new WebInspector.PropertiesSidebarPane();
+
+    this.sidebarPanes.styles.onexpand = this.updateStyles.bind(this);
+    this.sidebarPanes.metrics.onexpand = this.updateMetrics.bind(this);
+    this.sidebarPanes.properties.onexpand = this.updateProperties.bind(this);
+
+    this.sidebarPanes.styles.expanded = true;
+
+    this.sidebarPanes.styles.addEventListener("style edited", this._stylesPaneEdited, this);
+    this.sidebarPanes.styles.addEventListener("style property toggled", this._stylesPaneEdited, this);
+    this.sidebarPanes.metrics.addEventListener("metrics edited", this._metricsPaneEdited, this);
+
+    this.sidebarElement = document.createElement("div");
+    this.sidebarElement.id = "elements-sidebar";
+
+    this.sidebarElement.appendChild(this.sidebarPanes.styles.element);
+    this.sidebarElement.appendChild(this.sidebarPanes.metrics.element);
+    this.sidebarElement.appendChild(this.sidebarPanes.properties.element);
+
+    this.sidebarResizeElement = document.createElement("div");
+    this.sidebarResizeElement.className = "sidebar-resizer-vertical";
+    this.sidebarResizeElement.addEventListener("mousedown", this.rightSidebarResizerDragStart.bind(this), false);
+
+    this.nodeSearchButton = document.createElement("button");
+    this.nodeSearchButton.title = WebInspector.UIString("Select an element in the page to inspect it.");
+    this.nodeSearchButton.id = "node-search-status-bar-item";
+    this.nodeSearchButton.className = "status-bar-item";
+    this.nodeSearchButton.addEventListener("click", this._nodeSearchButtonClicked.bind(this), false);
+
+    this.searchingForNode = false;
+
+    this.element.appendChild(this.contentElement);
+    this.element.appendChild(this.sidebarElement);
+    this.element.appendChild(this.sidebarResizeElement);
+
+    this._mutationMonitoredWindows = [];
+    this._nodeInsertedEventListener = InspectorController.wrapCallback(this._nodeInserted.bind(this));
+    this._nodeRemovedEventListener = InspectorController.wrapCallback(this._nodeRemoved.bind(this));
+    this._contentLoadedEventListener = InspectorController.wrapCallback(this._contentLoaded.bind(this));
+
+    this.reset();
+}
+
+WebInspector.ElementsPanel.prototype = {
+    toolbarItemClass: "elements",
+
+    get toolbarItemLabel()
+    {
+        return WebInspector.UIString("Elements");
+    },
+
+    get statusBarItems()
+    {
+        return [this.nodeSearchButton, this.crumbsElement];
+    },
+
+    updateStatusBarItems: function()
+    {
+        this.updateBreadcrumbSizes();
+    },
+
+    show: function()
+    {
+        WebInspector.Panel.prototype.show.call(this);
+        this.sidebarResizeElement.style.right = (this.sidebarElement.offsetWidth - 3) + "px";
+        this.updateBreadcrumb();
+        this.treeOutline.updateSelection();
+        if (this.recentlyModifiedNodes.length)
+            this._updateModifiedNodes();
+    },
+
+    hide: function()
+    {
+        WebInspector.Panel.prototype.hide.call(this);
+
+        WebInspector.hoveredDOMNode = null;
+
+        if (InspectorController.searchingForNode()) {
+            InspectorController.toggleNodeSearch();
+            this.nodeSearchButton.removeStyleClass("toggled-on");
+        }
+    },
+
+    resize: function()
+    {
+        this.treeOutline.updateSelection();
+        this.updateBreadcrumbSizes();
+    },
+
+    reset: function()
+    {
+        this.rootDOMNode = null;
+        this.focusedDOMNode = null;
+
+        WebInspector.hoveredDOMNode = null;
+
+        if (InspectorController.searchingForNode()) {
+            InspectorController.toggleNodeSearch();
+            this.nodeSearchButton.removeStyleClass("toggled-on");
+        }
+
+        this.recentlyModifiedNodes = [];
+        this.unregisterAllMutationEventListeners();
+
+        delete this.currentQuery;
+        this.searchCanceled();
+
+        var inspectedWindow = InspectorController.inspectedWindow();
+        if (!inspectedWindow || !inspectedWindow.document)
+            return;
+
+        if (!inspectedWindow.document.firstChild) {
+            function contentLoaded()
+            {
+                inspectedWindow.document.removeEventListener("DOMContentLoaded", contentLoadedCallback, false);
+
+                this.reset();
+            }
+
+            var contentLoadedCallback = InspectorController.wrapCallback(contentLoaded.bind(this));
+            inspectedWindow.document.addEventListener("DOMContentLoaded", contentLoadedCallback, false);
+            return;
+        }
+
+        // If the window isn't visible, return early so the DOM tree isn't built
+        // and mutation event listeners are not added.
+        if (!InspectorController.isWindowVisible())
+            return;
+
+        this.registerMutationEventListeners(inspectedWindow);
+
+        var inspectedRootDocument = inspectedWindow.document;
+        this.rootDOMNode = inspectedRootDocument;
+
+        var canidateFocusNode = inspectedRootDocument.body || inspectedRootDocument.documentElement;
+        if (canidateFocusNode) {
+            this.treeOutline.suppressSelectHighlight = true;
+            this.focusedDOMNode = canidateFocusNode;
+            this.treeOutline.suppressSelectHighlight = false;
+
+            if (this.treeOutline.selectedTreeElement)
+                this.treeOutline.selectedTreeElement.expand();
+        }
+    },
+
+    includedInSearchResultsPropertyName: "__includedInInspectorSearchResults",
+
+    searchCanceled: function()
+    {
+        if (this._searchResults) {
+            const searchResultsProperty = this.includedInSearchResultsPropertyName;
+            for (var i = 0; i < this._searchResults.length; ++i) {
+                var node = this._searchResults[i];
+
+                // Remove the searchResultsProperty since there might be an unfinished search.
+                delete node[searchResultsProperty];
+
+                var treeElement = this.treeOutline.findTreeElement(node);
+                if (treeElement)
+                    treeElement.highlighted = false;
+            }
+        }
+
+        WebInspector.updateSearchMatchesCount(0, this);
+
+        if (this._currentSearchChunkIntervalIdentifier) {
+            clearInterval(this._currentSearchChunkIntervalIdentifier);
+            delete this._currentSearchChunkIntervalIdentifier;
+        }
+
+        this._currentSearchResultIndex = 0;
+        this._searchResults = [];
+    },
+
+    performSearch: function(query)
+    {
+        // Call searchCanceled since it will reset everything we need before doing a new search.
+        this.searchCanceled();
+
+        const whitespaceTrimmedQuery = query.trimWhitespace();
+        if (!whitespaceTrimmedQuery.length)
+            return;
+
+        var tagNameQuery = whitespaceTrimmedQuery;
+        var attributeNameQuery = whitespaceTrimmedQuery;
+        var startTagFound = (tagNameQuery.indexOf("<") === 0);
+        var endTagFound = (tagNameQuery.lastIndexOf(">") === (tagNameQuery.length - 1));
+
+        if (startTagFound || endTagFound) {
+            var tagNameQueryLength = tagNameQuery.length;
+            tagNameQuery = tagNameQuery.substring((startTagFound ? 1 : 0), (endTagFound ? (tagNameQueryLength - 1) : tagNameQueryLength));
+        }
+
+        // Check the tagNameQuery is it is a possibly valid tag name.
+        if (!/^[a-zA-Z0-9\-_:]+$/.test(tagNameQuery))
+            tagNameQuery = null;
+
+        // Check the attributeNameQuery is it is a possibly valid tag name.
+        if (!/^[a-zA-Z0-9\-_:]+$/.test(attributeNameQuery))
+            attributeNameQuery = null;
+
+        const escapedQuery = query.escapeCharacters("'");
+        const escapedTagNameQuery = (tagNameQuery ? tagNameQuery.escapeCharacters("'") : null);
+        const escapedWhitespaceTrimmedQuery = whitespaceTrimmedQuery.escapeCharacters("'");
+        const searchResultsProperty = this.includedInSearchResultsPropertyName;
+
+        var updatedMatchCountOnce = false;
+        var matchesCountUpdateTimeout = null;
+
+        function updateMatchesCount()
+        {
+            WebInspector.updateSearchMatchesCount(this._searchResults.length, this);
+            matchesCountUpdateTimeout = null;
+            updatedMatchCountOnce = true;
+        }
+
+        function updateMatchesCountSoon()
+        {
+            if (!updatedMatchCountOnce)
+                return updateMatchesCount.call(this);
+            if (matchesCountUpdateTimeout)
+                return;
+            // Update the matches count every half-second so it doesn't feel twitchy.
+            matchesCountUpdateTimeout = setTimeout(updateMatchesCount.bind(this), 500);
+        }
+
+        function addNodesToResults(nodes, length, getItem)
+        {
+            if (!length)
+                return;
+
+            for (var i = 0; i < length; ++i) {
+                var node = getItem.call(nodes, i);
+                // Skip this node if it already has the property.
+                if (searchResultsProperty in node)
+                    continue;
+
+                if (!this._searchResults.length) {
+                    this._currentSearchResultIndex = 0;
+                    this.focusedDOMNode = node;
+                }
+
+                node[searchResultsProperty] = true;
+                this._searchResults.push(node);
+
+                // Highlight the tree element to show it matched the search.
+                // FIXME: highlight the substrings in text nodes and attributes.
+                var treeElement = this.treeOutline.findTreeElement(node);
+                if (treeElement)
+                    treeElement.highlighted = true;
+            }
+
+            updateMatchesCountSoon.call(this);
+        }
+
+        function matchExactItems(doc)
+        {
+            matchExactId.call(this, doc);
+            matchExactClassNames.call(this, doc);
+            matchExactTagNames.call(this, doc);
+            matchExactAttributeNames.call(this, doc);
+        }
+
+        function matchExactId(doc)
+        {
+            const result = doc.__proto__.getElementById.call(doc, whitespaceTrimmedQuery);
+            addNodesToResults.call(this, result, (result ? 1 : 0), function() { return this });
+        }
+
+        function matchExactClassNames(doc)
+        {
+            const result = doc.__proto__.getElementsByClassName.call(doc, whitespaceTrimmedQuery);
+            addNodesToResults.call(this, result, result.length, result.item);
+        }
+
+        function matchExactTagNames(doc)
+        {
+            if (!tagNameQuery)
+                return;
+            const result = doc.__proto__.getElementsByTagName.call(doc, tagNameQuery);
+            addNodesToResults.call(this, result, result.length, result.item);
+        }
+
+        function matchExactAttributeNames(doc)
+        {
+            if (!attributeNameQuery)
+                return;
+            const result = doc.__proto__.querySelectorAll.call(doc, "[" + attributeNameQuery + "]");
+            addNodesToResults.call(this, result, result.length, result.item);
+        }
+
+        function matchPartialTagNames(doc)
+        {
+            if (!tagNameQuery)
+                return;
+            const result = doc.__proto__.evaluate.call(doc, "//*[contains(name(), '" + escapedTagNameQuery + "')]", doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
+            addNodesToResults.call(this, result, result.snapshotLength, result.snapshotItem);
+        }
+
+        function matchStartOfTagNames(doc)
+        {
+            if (!tagNameQuery)
+                return;
+            const result = doc.__proto__.evaluate.call(doc, "//*[starts-with(name(), '" + escapedTagNameQuery + "')]", doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
+            addNodesToResults.call(this, result, result.snapshotLength, result.snapshotItem);
+        }
+
+        function matchPartialTagNamesAndAttributeValues(doc)
+        {
+            if (!tagNameQuery) {
+                matchPartialAttributeValues.call(this, doc);
+                return;
+            }
+
+            const result = doc.__proto__.evaluate.call(doc, "//*[contains(name(), '" + escapedTagNameQuery + "') or contains(@*, '" + escapedQuery + "')]", doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
+            addNodesToResults.call(this, result, result.snapshotLength, result.snapshotItem);
+        }
+
+        function matchPartialAttributeValues(doc)
+        {
+            const result = doc.__proto__.evaluate.call(doc, "//*[contains(@*, '" + escapedQuery + "')]", doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
+            addNodesToResults.call(this, result, result.snapshotLength, result.snapshotItem);
+        }
+
+        function matchStyleSelector(doc)
+        {
+            const result = doc.__proto__.querySelectorAll.call(doc, whitespaceTrimmedQuery);
+            addNodesToResults.call(this, result, result.length, result.item);
+        }
+
+        function matchPlainText(doc)
+        {
+            const result = doc.__proto__.evaluate.call(doc, "//text()[contains(., '" + escapedQuery + "')] | //comment()[contains(., '" + escapedQuery + "')]", doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
+            addNodesToResults.call(this, result, result.snapshotLength, result.snapshotItem);
+        }
+
+        function matchXPathQuery(doc)
+        {
+            const result = doc.__proto__.evaluate.call(doc, whitespaceTrimmedQuery, doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
+            addNodesToResults.call(this, result, result.snapshotLength, result.snapshotItem);
+        }
+
+        function finishedSearching()
+        {
+            // Remove the searchResultsProperty now that the search is finished.
+            for (var i = 0; i < this._searchResults.length; ++i)
+                delete this._searchResults[i][searchResultsProperty];
+        }
+
+        const mainFrameDocument = InspectorController.inspectedWindow().document;
+        const searchDocuments = [mainFrameDocument];
+
+        if (tagNameQuery && startTagFound && endTagFound)
+            const searchFunctions = [matchExactTagNames, matchPlainText];
+        else if (tagNameQuery && startTagFound)
+            const searchFunctions = [matchStartOfTagNames, matchPlainText];
+        else if (tagNameQuery && endTagFound) {
+            // FIXME: we should have a matchEndOfTagNames search function if endTagFound is true but not startTagFound.
+            // This requires ends-with() support in XPath, WebKit only supports starts-with() and contains().
+            const searchFunctions = [matchPartialTagNames, matchPlainText];
+        } else if (whitespaceTrimmedQuery === "//*" || whitespaceTrimmedQuery === "*") {
+            // These queries will match every node. Matching everything isn't useful and can be slow for large pages,
+            // so limit the search functions list to plain text and attribute matching.
+            const searchFunctions = [matchPartialAttributeValues, matchPlainText];
+        } else
+            const searchFunctions = [matchExactItems, matchStyleSelector, matchPartialTagNamesAndAttributeValues, matchPlainText, matchXPathQuery];
+
+        // Find all frames, iframes and object elements to search their documents.
+        const querySelectorAllFunction = InspectorController.inspectedWindow().Document.prototype.querySelectorAll;
+        const subdocumentResult = querySelectorAllFunction.call(mainFrameDocument, "iframe, frame, object");
+
+        for (var i = 0; i < subdocumentResult.length; ++i) {
+            var element = subdocumentResult.item(i);
+            if (element.contentDocument)
+                searchDocuments.push(element.contentDocument);
+        }
+
+        const panel = this;
+        var documentIndex = 0;
+        var searchFunctionIndex = 0;
+        var chunkIntervalIdentifier = null;
+
+        // Split up the work into chunks so we don't block the UI thread while processing.
+
+        function processChunk()
+        {
+            var searchDocument = searchDocuments[documentIndex];
+            var searchFunction = searchFunctions[searchFunctionIndex];
+
+            if (++searchFunctionIndex > searchFunctions.length) {
+                searchFunction = searchFunctions[0];
+                searchFunctionIndex = 0;
+
+                if (++documentIndex > searchDocuments.length) {
+                    if (panel._currentSearchChunkIntervalIdentifier === chunkIntervalIdentifier)
+                        delete panel._currentSearchChunkIntervalIdentifier;
+                    clearInterval(chunkIntervalIdentifier);
+                    finishedSearching.call(panel);
+                    return;
+                }
+
+                searchDocument = searchDocuments[documentIndex];
+            }
+
+            if (!searchDocument || !searchFunction)
+                return;
+
+            try {
+                searchFunction.call(panel, searchDocument);
+            } catch(err) {
+                // ignore any exceptions. the query might be malformed, but we allow that.
+            }
+        }
+
+        processChunk();
+
+        chunkIntervalIdentifier = setInterval(processChunk, 25);
+        this._currentSearchChunkIntervalIdentifier = chunkIntervalIdentifier;
+    },
+
+    jumpToNextSearchResult: function()
+    {
+        if (!this._searchResults || !this._searchResults.length)
+            return;
+        if (++this._currentSearchResultIndex >= this._searchResults.length)
+            this._currentSearchResultIndex = 0;
+        this.focusedDOMNode = this._searchResults[this._currentSearchResultIndex];
+    },
+
+    jumpToPreviousSearchResult: function()
+    {
+        if (!this._searchResults || !this._searchResults.length)
+            return;
+        if (--this._currentSearchResultIndex < 0)
+            this._currentSearchResultIndex = (this._searchResults.length - 1);
+        this.focusedDOMNode = this._searchResults[this._currentSearchResultIndex];
+    },
+
+    inspectedWindowCleared: function(window)
+    {
+        if (InspectorController.isWindowVisible())
+            this.updateMutationEventListeners(window);
+    },
+
+    _addMutationEventListeners: function(monitoredWindow)
+    {
+        monitoredWindow.document.addEventListener("DOMNodeInserted", this._nodeInsertedEventListener, true);
+        monitoredWindow.document.addEventListener("DOMNodeRemoved", this._nodeRemovedEventListener, true);
+        if (monitoredWindow.frameElement)
+            monitoredWindow.addEventListener("DOMContentLoaded", this._contentLoadedEventListener, true);
+    },
+
+    _removeMutationEventListeners: function(monitoredWindow)
+    {
+        if (monitoredWindow.frameElement)
+            monitoredWindow.removeEventListener("DOMContentLoaded", this._contentLoadedEventListener, true);
+        if (!monitoredWindow.document)
+            return;
+        monitoredWindow.document.removeEventListener("DOMNodeInserted", this._nodeInsertedEventListener, true);
+        monitoredWindow.document.removeEventListener("DOMNodeRemoved", this._nodeRemovedEventListener, true);
+    },
+
+    updateMutationEventListeners: function(monitoredWindow)
+    {
+        this._addMutationEventListeners(monitoredWindow);
+    },
+
+    registerMutationEventListeners: function(monitoredWindow)
+    {
+        if (!monitoredWindow || this._mutationMonitoredWindows.indexOf(monitoredWindow) !== -1)
+            return;
+        this._mutationMonitoredWindows.push(monitoredWindow);
+        if (InspectorController.isWindowVisible())
+            this._addMutationEventListeners(monitoredWindow);
+    },
+
+    unregisterMutationEventListeners: function(monitoredWindow)
+    {
+        if (!monitoredWindow || this._mutationMonitoredWindows.indexOf(monitoredWindow) === -1)
+            return;
+        this._mutationMonitoredWindows.remove(monitoredWindow);
+        this._removeMutationEventListeners(monitoredWindow);
+    },
+
+    unregisterAllMutationEventListeners: function()
+    {
+        for (var i = 0; i < this._mutationMonitoredWindows.length; ++i)
+            this._removeMutationEventListeners(this._mutationMonitoredWindows[i]);
+        this._mutationMonitoredWindows = [];
+    },
+
+    get rootDOMNode()
+    {
+        return this.treeOutline.rootDOMNode;
+    },
+
+    set rootDOMNode(x)
+    {
+        this.treeOutline.rootDOMNode = x;
+    },
+
+    get focusedDOMNode()
+    {
+        return this.treeOutline.focusedDOMNode;
+    },
+
+    set focusedDOMNode(x)
+    {
+        this.treeOutline.focusedDOMNode = x;
+    },
+
+    _contentLoaded: function(event)
+    {
+        this.recentlyModifiedNodes.push({node: event.target, parent: event.target.defaultView.frameElement, replaced: true});
+        if (this.visible)
+            this._updateModifiedNodesSoon();
+    },
+
+    _nodeInserted: function(event)
+    {
+        this.recentlyModifiedNodes.push({node: event.target, parent: event.relatedNode, inserted: true});
+        if (this.visible)
+            this._updateModifiedNodesSoon();
+    },
+
+    _nodeRemoved: function(event)
+    {
+        this.recentlyModifiedNodes.push({node: event.target, parent: event.relatedNode, removed: true});
+        if (this.visible)
+            this._updateModifiedNodesSoon();
+    },
+
+    _updateModifiedNodesSoon: function()
+    {
+        if ("_updateModifiedNodesTimeout" in this)
+            return;
+        this._updateModifiedNodesTimeout = setTimeout(this._updateModifiedNodes.bind(this), 0);
+    },
+
+    _updateModifiedNodes: function()
+    {
+        if ("_updateModifiedNodesTimeout" in this) {
+            clearTimeout(this._updateModifiedNodesTimeout);
+            delete this._updateModifiedNodesTimeout;
+        }
+
+        var updatedParentTreeElements = [];
+        var updateBreadcrumbs = false;
+
+        for (var i = 0; i < this.recentlyModifiedNodes.length; ++i) {
+            var replaced = this.recentlyModifiedNodes[i].replaced;
+            var parent = this.recentlyModifiedNodes[i].parent;
+            if (!parent)
+                continue;
+
+            var parentNodeItem = this.treeOutline.findTreeElement(parent, null, null, objectsAreSame);
+            if (parentNodeItem && !parentNodeItem.alreadyUpdatedChildren) {
+                parentNodeItem.updateChildren(replaced);
+                parentNodeItem.alreadyUpdatedChildren = true;
+                updatedParentTreeElements.push(parentNodeItem);
+            }
+
+            if (!updateBreadcrumbs && (objectsAreSame(this.focusedDOMNode, parent) || isAncestorIncludingParentFrames(this.focusedDOMNode, parent)))
+                updateBreadcrumbs = true;
+        }
+
+        for (var i = 0; i < updatedParentTreeElements.length; ++i)
+            delete updatedParentTreeElements[i].alreadyUpdatedChildren;
+
+        this.recentlyModifiedNodes = [];
+
+        if (updateBreadcrumbs)
+            this.updateBreadcrumb(true);
+    },
+
+    _stylesPaneEdited: function()
+    {
+        this.sidebarPanes.metrics.needsUpdate = true;
+        this.updateMetrics();
+    },
+
+    _metricsPaneEdited: function()
+    {
+        this.sidebarPanes.styles.needsUpdate = true;
+        this.updateStyles(true);
+    },
+
+    _mouseMovedInCrumbs: function(event)
+    {
+        var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY);
+        var crumbElement = nodeUnderMouse.enclosingNodeOrSelfWithClass("crumb");
+
+        WebInspector.hoveredDOMNode = (crumbElement ? crumbElement.representedObject : null);
+
+        if ("_mouseOutOfCrumbsTimeout" in this) {
+            clearTimeout(this._mouseOutOfCrumbsTimeout);
+            delete this._mouseOutOfCrumbsTimeout;
+        }
+    },
+
+    _mouseMovedOutOfCrumbs: function(event)
+    {
+        var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY);
+        if (nodeUnderMouse.isDescendant(this.crumbsElement))
+            return;
+
+        WebInspector.hoveredDOMNode = null;
+
+        this._mouseOutOfCrumbsTimeout = setTimeout(this.updateBreadcrumbSizes.bind(this), 1000);
+    },
+
+    updateBreadcrumb: function(forceUpdate)
+    {
+        if (!this.visible)
+            return;
+
+        var crumbs = this.crumbsElement;
+
+        var handled = false;
+        var foundRoot = false;
+        var crumb = crumbs.firstChild;
+        while (crumb) {
+            if (objectsAreSame(crumb.representedObject, this.rootDOMNode))
+                foundRoot = true;
+
+            if (foundRoot)
+                crumb.addStyleClass("dimmed");
+            else
+                crumb.removeStyleClass("dimmed");
+
+            if (objectsAreSame(crumb.representedObject, this.focusedDOMNode)) {
+                crumb.addStyleClass("selected");
+                handled = true;
+            } else {
+                crumb.removeStyleClass("selected");
+            }
+
+            crumb = crumb.nextSibling;
+        }
+
+        if (handled && !forceUpdate) {
+            // We don't need to rebuild the crumbs, but we need to adjust sizes
+            // to reflect the new focused or root node.
+            this.updateBreadcrumbSizes();
+            return;
+        }
+
+        crumbs.removeChildren();
+
+        var panel = this;
+
+        function selectCrumbFunction(event)
+        {
+            var crumb = event.currentTarget;
+            if (crumb.hasStyleClass("collapsed")) {
+                // Clicking a collapsed crumb will expose the hidden crumbs.
+                if (crumb === panel.crumbsElement.firstChild) {
+                    // If the focused crumb is the first child, pick the farthest crumb
+                    // that is still hidden. This allows the user to expose every crumb.
+                    var currentCrumb = crumb;
+                    while (currentCrumb) {
+                        var hidden = currentCrumb.hasStyleClass("hidden");
+                        var collapsed = currentCrumb.hasStyleClass("collapsed");
+                        if (!hidden && !collapsed)
+                            break;
+                        crumb = currentCrumb;
+                        currentCrumb = currentCrumb.nextSibling;
+                    }
+                }
+
+                panel.updateBreadcrumbSizes(crumb);
+            } else {
+                // Clicking a dimmed crumb or double clicking (event.detail >= 2)
+                // will change the root node in addition to the focused node.
+                if (event.detail >= 2 || crumb.hasStyleClass("dimmed"))
+                    panel.rootDOMNode = crumb.representedObject.parentNode;
+                panel.focusedDOMNode = crumb.representedObject;
+            }
+
+            event.preventDefault();
+        }
+
+        foundRoot = false;
+        for (var current = this.focusedDOMNode; current; current = parentNodeOrFrameElement(current)) {
+            if (current.nodeType === Node.DOCUMENT_NODE)
+                continue;
+
+            if (objectsAreSame(current, this.rootDOMNode))
+                foundRoot = true;
+
+            var crumb = document.createElement("span");
+            crumb.className = "crumb";
+            crumb.representedObject = current;
+            crumb.addEventListener("mousedown", selectCrumbFunction, false);
+
+            var crumbTitle;
+            switch (current.nodeType) {
+                case Node.ELEMENT_NODE:
+                    crumbTitle = current.nodeName.toLowerCase();
+
+                    var nameElement = document.createElement("span");
+                    nameElement.textContent = crumbTitle;
+                    crumb.appendChild(nameElement);
+
+                    var idAttribute = current.getAttribute("id");
+                    if (idAttribute) {
+                        var idElement = document.createElement("span");
+                        crumb.appendChild(idElement);
+
+                        var part = "#" + idAttribute;
+                        crumbTitle += part;
+                        idElement.appendChild(document.createTextNode(part));
+
+                        // Mark the name as extra, since the ID is more important.
+                        nameElement.className = "extra";
+                    }
+
+                    var classAttribute = current.getAttribute("class");
+                    if (classAttribute) {
+                        var classes = classAttribute.split(/\s+/);
+                        var foundClasses = {};
+
+                        if (classes.length) {
+                            var classesElement = document.createElement("span");
+                            classesElement.className = "extra";
+                            crumb.appendChild(classesElement);
+
+                            for (var i = 0; i < classes.length; ++i) {
+                                var className = classes[i];
+                                if (className && !(className in foundClasses)) {
+                                    var part = "." + className;
+                                    crumbTitle += part;
+                                    classesElement.appendChild(document.createTextNode(part));
+                                    foundClasses[className] = true;
+                                }
+                            }
+                        }
+                    }
+
+                    break;
+
+                case Node.TEXT_NODE:
+                    if (isNodeWhitespace.call(current))
+                        crumbTitle = WebInspector.UIString("(whitespace)");
+                    else
+                        crumbTitle = WebInspector.UIString("(text)");
+                    break
+
+                case Node.COMMENT_NODE:
+                    crumbTitle = "<!-->";
+                    break;
+
+                case Node.DOCUMENT_TYPE_NODE:
+                    crumbTitle = "<!DOCTYPE>";
+                    break;
+
+                default:
+                    crumbTitle = current.nodeName.toLowerCase();
+            }
+
+            if (!crumb.childNodes.length) {
+                var nameElement = document.createElement("span");
+                nameElement.textContent = crumbTitle;
+                crumb.appendChild(nameElement);
+            }
+
+            crumb.title = crumbTitle;
+
+            if (foundRoot)
+                crumb.addStyleClass("dimmed");
+            if (objectsAreSame(current, this.focusedDOMNode))
+                crumb.addStyleClass("selected");
+            if (!crumbs.childNodes.length)
+                crumb.addStyleClass("end");
+
+            crumbs.appendChild(crumb);
+        }
+
+        if (crumbs.hasChildNodes())
+            crumbs.lastChild.addStyleClass("start");
+
+        this.updateBreadcrumbSizes();
+    },
+
+    updateBreadcrumbSizes: function(focusedCrumb)
+    {
+        if (!this.visible)
+            return;
+
+        if (document.body.offsetWidth <= 0) {
+            // The stylesheet hasn't loaded yet or the window is closed,
+            // so we can't calculate what is need. Return early.
+            return;
+        }
+
+        var crumbs = this.crumbsElement;
+        if (!crumbs.childNodes.length || crumbs.offsetWidth <= 0)
+            return; // No crumbs, do nothing.
+
+        // A Zero index is the right most child crumb in the breadcrumb.
+        var selectedIndex = 0;
+        var focusedIndex = 0;
+        var selectedCrumb;
+
+        var i = 0;
+        var crumb = crumbs.firstChild;
+        while (crumb) {
+            // Find the selected crumb and index. 
+            if (!selectedCrumb && crumb.hasStyleClass("selected")) {
+                selectedCrumb = crumb;
+                selectedIndex = i;
+            }
+
+            // Find the focused crumb index. 
+            if (crumb === focusedCrumb)
+                focusedIndex = i;
+
+            // Remove any styles that affect size before
+            // deciding to shorten any crumbs.
+            if (crumb !== crumbs.lastChild)
+                crumb.removeStyleClass("start");
+            if (crumb !== crumbs.firstChild)
+                crumb.removeStyleClass("end");
+
+            crumb.removeStyleClass("compact");
+            crumb.removeStyleClass("collapsed");
+            crumb.removeStyleClass("hidden");
+
+            crumb = crumb.nextSibling;
+            ++i;
+        }
+
+        // Restore the start and end crumb classes in case they got removed in coalesceCollapsedCrumbs().
+        // The order of the crumbs in the document is opposite of the visual order.
+        crumbs.firstChild.addStyleClass("end");
+        crumbs.lastChild.addStyleClass("start");
+
+        function crumbsAreSmallerThanContainer()
+        {
+            var rightPadding = 20;
+            var errorWarningElement = document.getElementById("error-warning-count");
+            if (!WebInspector.console.visible && errorWarningElement)
+                rightPadding += errorWarningElement.offsetWidth;
+            return ((crumbs.totalOffsetLeft + crumbs.offsetWidth + rightPadding) < window.innerWidth);
+        }
+
+        if (crumbsAreSmallerThanContainer())
+            return; // No need to compact the crumbs, they all fit at full size.
+
+        var BothSides = 0;
+        var AncestorSide = -1;
+        var ChildSide = 1;
+
+        function makeCrumbsSmaller(shrinkingFunction, direction, significantCrumb)
+        {
+            if (!significantCrumb)
+                significantCrumb = (focusedCrumb || selectedCrumb);
+
+            if (significantCrumb === selectedCrumb)
+                var significantIndex = selectedIndex;
+            else if (significantCrumb === focusedCrumb)
+                var significantIndex = focusedIndex;
+            else {
+                var significantIndex = 0;
+                for (var i = 0; i < crumbs.childNodes.length; ++i) {
+                    if (crumbs.childNodes[i] === significantCrumb) {
+                        significantIndex = i;
+                        break;
+                    }
+                }
+            }
+
+            function shrinkCrumbAtIndex(index)
+            {
+                var shrinkCrumb = crumbs.childNodes[index];
+                if (shrinkCrumb && shrinkCrumb !== significantCrumb)
+                    shrinkingFunction(shrinkCrumb);
+                if (crumbsAreSmallerThanContainer())
+                    return true; // No need to compact the crumbs more.
+                return false;
+            }
+
+            // Shrink crumbs one at a time by applying the shrinkingFunction until the crumbs
+            // fit in the container or we run out of crumbs to shrink.
+            if (direction) {
+                // Crumbs are shrunk on only one side (based on direction) of the signifcant crumb.
+                var index = (direction > 0 ? 0 : crumbs.childNodes.length - 1);
+                while (index !== significantIndex) {
+                    if (shrinkCrumbAtIndex(index))
+                        return true;
+                    index += (direction > 0 ? 1 : -1);
+                }
+            } else {
+                // Crumbs are shrunk in order of descending distance from the signifcant crumb,
+                // with a tie going to child crumbs.
+                var startIndex = 0;
+                var endIndex = crumbs.childNodes.length - 1;
+                while (startIndex != significantIndex || endIndex != significantIndex) {
+                    var startDistance = significantIndex - startIndex;
+                    var endDistance = endIndex - significantIndex;
+                    if (startDistance >= endDistance)
+                        var index = startIndex++;
+                    else
+                        var index = endIndex--;
+                    if (shrinkCrumbAtIndex(index))
+                        return true;
+                }
+            }
+
+            // We are not small enough yet, return false so the caller knows.
+            return false;
+        }
+
+        function coalesceCollapsedCrumbs()
+        {
+            var crumb = crumbs.firstChild;
+            var collapsedRun = false;
+            var newStartNeeded = false;
+            var newEndNeeded = false;
+            while (crumb) {
+                var hidden = crumb.hasStyleClass("hidden");
+                if (!hidden) {
+                    var collapsed = crumb.hasStyleClass("collapsed"); 
+                    if (collapsedRun && collapsed) {
+                        crumb.addStyleClass("hidden");
+                        crumb.removeStyleClass("compact");
+                        crumb.removeStyleClass("collapsed");
+
+                        if (crumb.hasStyleClass("start")) {
+                            crumb.removeStyleClass("start");
+                            newStartNeeded = true;
+                        }
+
+                        if (crumb.hasStyleClass("end")) {
+                            crumb.removeStyleClass("end");
+                            newEndNeeded = true;
+                        }
+
+                        continue;
+                    }
+
+                    collapsedRun = collapsed;
+
+                    if (newEndNeeded) {
+                        newEndNeeded = false;
+                        crumb.addStyleClass("end");
+                    }
+                } else
+                    collapsedRun = true;
+                crumb = crumb.nextSibling;
+            }
+
+            if (newStartNeeded) {
+                crumb = crumbs.lastChild;
+                while (crumb) {
+                    if (!crumb.hasStyleClass("hidden")) {
+                        crumb.addStyleClass("start");
+                        break;
+                    }
+                    crumb = crumb.previousSibling;
+                }
+            }
+        }
+
+        function compact(crumb)
+        {
+            if (crumb.hasStyleClass("hidden"))
+                return;
+            crumb.addStyleClass("compact");
+        }
+
+        function collapse(crumb, dontCoalesce)
+        {
+            if (crumb.hasStyleClass("hidden"))
+                return;
+            crumb.addStyleClass("collapsed");
+            crumb.removeStyleClass("compact");
+            if (!dontCoalesce)
+                coalesceCollapsedCrumbs();
+        }
+
+        function compactDimmed(crumb)
+        {
+            if (crumb.hasStyleClass("dimmed"))
+                compact(crumb);
+        }
+
+        function collapseDimmed(crumb)
+        {
+            if (crumb.hasStyleClass("dimmed"))
+                collapse(crumb);
+        }
+
+        if (!focusedCrumb) {
+            // When not focused on a crumb we can be biased and collapse less important
+            // crumbs that the user might not care much about.
+
+            // Compact child crumbs.
+            if (makeCrumbsSmaller(compact, ChildSide))
+                return;
+
+            // Collapse child crumbs.
+            if (makeCrumbsSmaller(collapse, ChildSide))
+                return;
+
+            // Compact dimmed ancestor crumbs.
+            if (makeCrumbsSmaller(compactDimmed, AncestorSide))
+                return;
+
+            // Collapse dimmed ancestor crumbs.
+            if (makeCrumbsSmaller(collapseDimmed, AncestorSide))
+                return;
+        }
+
+        // Compact ancestor crumbs, or from both sides if focused.
+        if (makeCrumbsSmaller(compact, (focusedCrumb ? BothSides : AncestorSide)))
+            return;
+
+        // Collapse ancestor crumbs, or from both sides if focused.
+        if (makeCrumbsSmaller(collapse, (focusedCrumb ? BothSides : AncestorSide)))
+            return;
+
+        if (!selectedCrumb)
+            return;
+
+        // Compact the selected crumb.
+        compact(selectedCrumb);
+        if (crumbsAreSmallerThanContainer())
+            return;
+
+        // Collapse the selected crumb as a last resort. Pass true to prevent coalescing.
+        collapse(selectedCrumb, true);
+    },
+
+    updateStyles: function(forceUpdate)
+    {
+        var stylesSidebarPane = this.sidebarPanes.styles;
+        if (!stylesSidebarPane.expanded || !stylesSidebarPane.needsUpdate)
+            return;
+
+        stylesSidebarPane.update(this.focusedDOMNode, null, forceUpdate);
+        stylesSidebarPane.needsUpdate = false;
+    },
+
+    updateMetrics: function()
+    {
+        var metricsSidebarPane = this.sidebarPanes.metrics;
+        if (!metricsSidebarPane.expanded || !metricsSidebarPane.needsUpdate)
+            return;
+
+        metricsSidebarPane.update(this.focusedDOMNode);
+        metricsSidebarPane.needsUpdate = false;
+    },
+
+    updateProperties: function()
+    {
+        var propertiesSidebarPane = this.sidebarPanes.properties;
+        if (!propertiesSidebarPane.expanded || !propertiesSidebarPane.needsUpdate)
+            return;
+
+        propertiesSidebarPane.update(this.focusedDOMNode);
+        propertiesSidebarPane.needsUpdate = false;
+    },
+
+    handleKeyEvent: function(event)
+    {
+        this.treeOutline.handleKeyEvent(event);
+    },
+
+    handleCopyEvent: function(event)
+    {
+        // Don't prevent the normal copy if the user has a selection.
+        if (!window.getSelection().isCollapsed)
+            return;
+
+        switch (this.focusedDOMNode.nodeType) {
+            case Node.ELEMENT_NODE:
+                var data = this.focusedDOMNode.outerHTML;
+                break;
+
+            case Node.COMMENT_NODE:
+                var data = "<!--" + this.focusedDOMNode.nodeValue + "-->";
+                break;
+
+            default:
+            case Node.TEXT_NODE:
+                var data = this.focusedDOMNode.nodeValue;
+        }
+
+        event.clipboardData.clearData();
+        event.preventDefault();
+
+        if (data)
+            event.clipboardData.setData("text/plain", data);
+    },
+
+    rightSidebarResizerDragStart: function(event)
+    {
+        WebInspector.elementDragStart(this.sidebarElement, this.rightSidebarResizerDrag.bind(this), this.rightSidebarResizerDragEnd.bind(this), event, "col-resize");
+    },
+
+    rightSidebarResizerDragEnd: function(event)
+    {
+        WebInspector.elementDragEnd(event);
+    },
+
+    rightSidebarResizerDrag: function(event)
+    {
+        var x = event.pageX;
+        var newWidth = Number.constrain(window.innerWidth - x, Preferences.minElementsSidebarWidth, window.innerWidth * 0.66);
+
+        this.sidebarElement.style.width = newWidth + "px";
+        this.contentElement.style.right = newWidth + "px";
+        this.sidebarResizeElement.style.right = (newWidth - 3) + "px";
+
+        this.treeOutline.updateSelection();
+
+        event.preventDefault();
+    },
+
+    _nodeSearchButtonClicked: function(event)
+    {
+        InspectorController.toggleNodeSearch();
+
+        if (InspectorController.searchingForNode())
+            this.nodeSearchButton.addStyleClass("toggled-on");
+        else
+            this.nodeSearchButton.removeStyleClass("toggled-on");
+    }
+}
+
+WebInspector.ElementsPanel.prototype.__proto__ = WebInspector.Panel.prototype;
diff --git a/resources/Inspector/FontView.js b/resources/Inspector/FontView.js
new file mode 100644
index 0000000..4e1c931
--- /dev/null
+++ b/resources/Inspector/FontView.js
@@ -0,0 +1,104 @@
+/*
+ * 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.FontView = function(resource)
+{
+    WebInspector.ResourceView.call(this, resource);
+
+    this.element.addStyleClass("font");
+
+    var uniqueFontName = "WebInspectorFontPreview" + this.resource.identifier;
+
+    this.fontStyleElement = document.createElement("style");
+    this.fontStyleElement.textContent = "@font-face { font-family: \"" + uniqueFontName + "\"; src: url(" + this.resource.url + "); }";
+    document.getElementsByTagName("head").item(0).appendChild(this.fontStyleElement);
+
+    this.fontPreviewElement = document.createElement("div");
+    this.fontPreviewElement.className = "preview";
+    this.contentElement.appendChild(this.fontPreviewElement);
+
+    this.fontPreviewElement.style.setProperty("font-family", uniqueFontName, null);
+    this.fontPreviewElement.innerHTML = "ABCDEFGHIJKLM<br>NOPQRSTUVWXYZ<br>abcdefghijklm<br>nopqrstuvwxyz<br>1234567890";
+
+    this.updateFontPreviewSize();
+}
+
+WebInspector.FontView.prototype = {
+    show: function(parentElement)
+    {
+        WebInspector.ResourceView.prototype.show.call(this, parentElement);
+        this.updateFontPreviewSize();
+    },
+
+    resize: function()
+    {
+        this.updateFontPreviewSize();
+    },
+
+    updateFontPreviewSize: function ()
+    {
+        if (!this.fontPreviewElement || !this.visible)
+            return;
+
+        this.fontPreviewElement.removeStyleClass("preview");
+
+        var measureFontSize = 50;
+        this.fontPreviewElement.style.setProperty("position", "absolute", null);
+        this.fontPreviewElement.style.setProperty("font-size", measureFontSize + "px", null);
+        this.fontPreviewElement.style.removeProperty("height");
+
+        var height = this.fontPreviewElement.offsetHeight;
+        var width = this.fontPreviewElement.offsetWidth;
+
+        var containerWidth = this.contentElement.offsetWidth;
+
+        // Subtract some padding. This should match the padding in the CSS plus room for the scrollbar.
+        containerWidth -= 40;
+
+        if (!height || !width || !containerWidth) {
+            this.fontPreviewElement.style.removeProperty("font-size");
+            this.fontPreviewElement.style.removeProperty("position");
+            this.fontPreviewElement.addStyleClass("preview");
+            return;
+        }
+
+        var lineCount = this.fontPreviewElement.getElementsByTagName("br").length + 1;
+        var realLineHeight = Math.floor(height / lineCount);
+        var fontSizeLineRatio = measureFontSize / realLineHeight;
+        var widthRatio = containerWidth / width;
+        var finalFontSize = Math.floor(realLineHeight * widthRatio * fontSizeLineRatio) - 1;
+
+        this.fontPreviewElement.style.setProperty("font-size", finalFontSize + "px", null);
+        this.fontPreviewElement.style.setProperty("height", this.fontPreviewElement.offsetHeight + "px", null);
+        this.fontPreviewElement.style.removeProperty("position");
+
+        this.fontPreviewElement.addStyleClass("preview");
+    }
+}
+
+WebInspector.FontView.prototype.__proto__ = WebInspector.ResourceView.prototype;
diff --git a/resources/Inspector/ImageView.js b/resources/Inspector/ImageView.js
new file mode 100644
index 0000000..001ffdd
--- /dev/null
+++ b/resources/Inspector/ImageView.js
@@ -0,0 +1,74 @@
+/*
+ * 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.ImageView = function(resource)
+{
+    WebInspector.ResourceView.call(this, resource);
+
+    this.element.addStyleClass("image");
+
+    var container = document.createElement("div");
+    container.className = "image";
+    this.contentElement.appendChild(container);
+
+    this.imagePreviewElement = document.createElement("img");
+    this.imagePreviewElement.setAttribute("src", this.resource.url);
+
+    container.appendChild(this.imagePreviewElement);
+
+    container = document.createElement("div");
+    container.className = "info";
+    this.contentElement.appendChild(container);
+
+    var imageNameElement = document.createElement("h1");
+    imageNameElement.className = "title";
+    imageNameElement.textContent = this.resource.displayName;
+    container.appendChild(imageNameElement);
+
+    var infoListElement = document.createElement("dl");
+    infoListElement.className = "infoList";
+
+    var imageProperties = [
+        { name: WebInspector.UIString("Dimensions"), value: WebInspector.UIString("%d × %d", this.imagePreviewElement.naturalWidth, this.imagePreviewElement.height) },
+        { name: WebInspector.UIString("File size"), value: Number.bytesToString(this.resource.contentLength, WebInspector.UIString.bind(WebInspector)) },
+        { name: WebInspector.UIString("MIME type"), value: this.resource.mimeType }
+    ];
+
+    var listHTML = '';
+    for (var i = 0; i < imageProperties.length; ++i)
+        listHTML += "<dt>" + imageProperties[i].name + "</dt><dd>" + imageProperties[i].value + "</dd>";
+
+    infoListElement.innerHTML = listHTML;
+    container.appendChild(infoListElement);
+}
+
+WebInspector.ImageView.prototype = {
+    
+}
+
+WebInspector.ImageView.prototype.__proto__ = WebInspector.ResourceView.prototype;
diff --git a/resources/Inspector/Images/back.png b/resources/Inspector/Images/back.png
new file mode 100644
index 0000000..9363960
--- /dev/null
+++ b/resources/Inspector/Images/back.png
Binary files differ
diff --git a/resources/Inspector/Images/checker.png b/resources/Inspector/Images/checker.png
new file mode 100644
index 0000000..8349908
--- /dev/null
+++ b/resources/Inspector/Images/checker.png
Binary files differ
diff --git a/resources/Inspector/Images/clearConsoleButtons.png b/resources/Inspector/Images/clearConsoleButtons.png
new file mode 100644
index 0000000..140a4fb
--- /dev/null
+++ b/resources/Inspector/Images/clearConsoleButtons.png
Binary files differ
diff --git a/resources/Inspector/Images/consoleButtons.png b/resources/Inspector/Images/consoleButtons.png
new file mode 100644
index 0000000..fb5f089
--- /dev/null
+++ b/resources/Inspector/Images/consoleButtons.png
Binary files differ
diff --git a/resources/Inspector/Images/database.png b/resources/Inspector/Images/database.png
new file mode 100644
index 0000000..339efa6
--- /dev/null
+++ b/resources/Inspector/Images/database.png
Binary files differ
diff --git a/resources/Inspector/Images/databaseTable.png b/resources/Inspector/Images/databaseTable.png
new file mode 100644
index 0000000..3718708
--- /dev/null
+++ b/resources/Inspector/Images/databaseTable.png
Binary files differ
diff --git a/resources/Inspector/Images/databasesIcon.png b/resources/Inspector/Images/databasesIcon.png
new file mode 100644
index 0000000..79c7bb3
--- /dev/null
+++ b/resources/Inspector/Images/databasesIcon.png
Binary files differ
diff --git a/resources/Inspector/Images/debuggerContinue.png b/resources/Inspector/Images/debuggerContinue.png
new file mode 100644
index 0000000..d90a855
--- /dev/null
+++ b/resources/Inspector/Images/debuggerContinue.png
Binary files differ
diff --git a/resources/Inspector/Images/debuggerPause.png b/resources/Inspector/Images/debuggerPause.png
new file mode 100644
index 0000000..97f958a
--- /dev/null
+++ b/resources/Inspector/Images/debuggerPause.png
Binary files differ
diff --git a/resources/Inspector/Images/debuggerStepInto.png b/resources/Inspector/Images/debuggerStepInto.png
new file mode 100644
index 0000000..277f126
--- /dev/null
+++ b/resources/Inspector/Images/debuggerStepInto.png
Binary files differ
diff --git a/resources/Inspector/Images/debuggerStepOut.png b/resources/Inspector/Images/debuggerStepOut.png
new file mode 100644
index 0000000..3032e32
--- /dev/null
+++ b/resources/Inspector/Images/debuggerStepOut.png
Binary files differ
diff --git a/resources/Inspector/Images/debuggerStepOver.png b/resources/Inspector/Images/debuggerStepOver.png
new file mode 100644
index 0000000..7d47245
--- /dev/null
+++ b/resources/Inspector/Images/debuggerStepOver.png
Binary files differ
diff --git a/resources/Inspector/Images/debuggingButtons.png b/resources/Inspector/Images/debuggingButtons.png
new file mode 100644
index 0000000..c9cc618
--- /dev/null
+++ b/resources/Inspector/Images/debuggingButtons.png
Binary files differ
diff --git a/resources/Inspector/Images/disclosureTriangleSmallDown.png b/resources/Inspector/Images/disclosureTriangleSmallDown.png
new file mode 100644
index 0000000..cffc835
--- /dev/null
+++ b/resources/Inspector/Images/disclosureTriangleSmallDown.png
Binary files differ
diff --git a/resources/Inspector/Images/disclosureTriangleSmallDownBlack.png b/resources/Inspector/Images/disclosureTriangleSmallDownBlack.png
new file mode 100644
index 0000000..4b49c13
--- /dev/null
+++ b/resources/Inspector/Images/disclosureTriangleSmallDownBlack.png
Binary files differ
diff --git a/resources/Inspector/Images/disclosureTriangleSmallDownWhite.png b/resources/Inspector/Images/disclosureTriangleSmallDownWhite.png
new file mode 100644
index 0000000..aebae12
--- /dev/null
+++ b/resources/Inspector/Images/disclosureTriangleSmallDownWhite.png
Binary files differ
diff --git a/resources/Inspector/Images/disclosureTriangleSmallRight.png b/resources/Inspector/Images/disclosureTriangleSmallRight.png
new file mode 100644
index 0000000..a3102ea
--- /dev/null
+++ b/resources/Inspector/Images/disclosureTriangleSmallRight.png
Binary files differ
diff --git a/resources/Inspector/Images/disclosureTriangleSmallRightBlack.png b/resources/Inspector/Images/disclosureTriangleSmallRightBlack.png
new file mode 100644
index 0000000..2c45859
--- /dev/null
+++ b/resources/Inspector/Images/disclosureTriangleSmallRightBlack.png
Binary files differ
diff --git a/resources/Inspector/Images/disclosureTriangleSmallRightDown.png b/resources/Inspector/Images/disclosureTriangleSmallRightDown.png
new file mode 100644
index 0000000..035c069
--- /dev/null
+++ b/resources/Inspector/Images/disclosureTriangleSmallRightDown.png
Binary files differ
diff --git a/resources/Inspector/Images/disclosureTriangleSmallRightDownBlack.png b/resources/Inspector/Images/disclosureTriangleSmallRightDownBlack.png
new file mode 100644
index 0000000..86f67bd
--- /dev/null
+++ b/resources/Inspector/Images/disclosureTriangleSmallRightDownBlack.png
Binary files differ
diff --git a/resources/Inspector/Images/disclosureTriangleSmallRightDownWhite.png b/resources/Inspector/Images/disclosureTriangleSmallRightDownWhite.png
new file mode 100644
index 0000000..972d794
--- /dev/null
+++ b/resources/Inspector/Images/disclosureTriangleSmallRightDownWhite.png
Binary files differ
diff --git a/resources/Inspector/Images/disclosureTriangleSmallRightWhite.png b/resources/Inspector/Images/disclosureTriangleSmallRightWhite.png
new file mode 100644
index 0000000..a10168f
--- /dev/null
+++ b/resources/Inspector/Images/disclosureTriangleSmallRightWhite.png
Binary files differ
diff --git a/resources/Inspector/Images/dockButtons.png b/resources/Inspector/Images/dockButtons.png
new file mode 100644
index 0000000..4b01d66
--- /dev/null
+++ b/resources/Inspector/Images/dockButtons.png
Binary files differ
diff --git a/resources/Inspector/Images/elementsIcon.png b/resources/Inspector/Images/elementsIcon.png
new file mode 100644
index 0000000..fde3db9
--- /dev/null
+++ b/resources/Inspector/Images/elementsIcon.png
Binary files differ
diff --git a/resources/Inspector/Images/errorIcon.png b/resources/Inspector/Images/errorIcon.png
new file mode 100644
index 0000000..c697263
--- /dev/null
+++ b/resources/Inspector/Images/errorIcon.png
Binary files differ
diff --git a/resources/Inspector/Images/errorMediumIcon.png b/resources/Inspector/Images/errorMediumIcon.png
new file mode 100644
index 0000000..6ca32bb
--- /dev/null
+++ b/resources/Inspector/Images/errorMediumIcon.png
Binary files differ
diff --git a/resources/Inspector/Images/forward.png b/resources/Inspector/Images/forward.png
new file mode 100644
index 0000000..ad70f3e
--- /dev/null
+++ b/resources/Inspector/Images/forward.png
Binary files differ
diff --git a/resources/Inspector/Images/glossyHeader.png b/resources/Inspector/Images/glossyHeader.png
new file mode 100644
index 0000000..6cbefb7
--- /dev/null
+++ b/resources/Inspector/Images/glossyHeader.png
Binary files differ
diff --git a/resources/Inspector/Images/glossyHeaderPressed.png b/resources/Inspector/Images/glossyHeaderPressed.png
new file mode 100644
index 0000000..1153506
--- /dev/null
+++ b/resources/Inspector/Images/glossyHeaderPressed.png
Binary files differ
diff --git a/resources/Inspector/Images/goArrow.png b/resources/Inspector/Images/goArrow.png
new file mode 100644
index 0000000..f318a56
--- /dev/null
+++ b/resources/Inspector/Images/goArrow.png
Binary files differ
diff --git a/resources/Inspector/Images/largerResourcesButtons.png b/resources/Inspector/Images/largerResourcesButtons.png
new file mode 100644
index 0000000..caf3f14
--- /dev/null
+++ b/resources/Inspector/Images/largerResourcesButtons.png
Binary files differ
diff --git a/resources/Inspector/Images/paneBottomGrow.png b/resources/Inspector/Images/paneBottomGrow.png
new file mode 100644
index 0000000..d55b865
--- /dev/null
+++ b/resources/Inspector/Images/paneBottomGrow.png
Binary files differ
diff --git a/resources/Inspector/Images/paneBottomGrowActive.png b/resources/Inspector/Images/paneBottomGrowActive.png
new file mode 100644
index 0000000..ef3f259
--- /dev/null
+++ b/resources/Inspector/Images/paneBottomGrowActive.png
Binary files differ
diff --git a/resources/Inspector/Images/paneGrowHandleLine.png b/resources/Inspector/Images/paneGrowHandleLine.png
new file mode 100644
index 0000000..4eaf61b
--- /dev/null
+++ b/resources/Inspector/Images/paneGrowHandleLine.png
Binary files differ
diff --git a/resources/Inspector/Images/resourceCSSIcon.png b/resources/Inspector/Images/resourceCSSIcon.png
new file mode 100644
index 0000000..aead6a7
--- /dev/null
+++ b/resources/Inspector/Images/resourceCSSIcon.png
Binary files differ
diff --git a/resources/Inspector/Images/resourceDocumentIcon.png b/resources/Inspector/Images/resourceDocumentIcon.png
new file mode 100644
index 0000000..1683a09
--- /dev/null
+++ b/resources/Inspector/Images/resourceDocumentIcon.png
Binary files differ
diff --git a/resources/Inspector/Images/resourceDocumentIconSmall.png b/resources/Inspector/Images/resourceDocumentIconSmall.png
new file mode 100644
index 0000000..468ced9
--- /dev/null
+++ b/resources/Inspector/Images/resourceDocumentIconSmall.png
Binary files differ
diff --git a/resources/Inspector/Images/resourceJSIcon.png b/resources/Inspector/Images/resourceJSIcon.png
new file mode 100644
index 0000000..9ef6ed0
--- /dev/null
+++ b/resources/Inspector/Images/resourceJSIcon.png
Binary files differ
diff --git a/resources/Inspector/Images/resourcePlainIcon.png b/resources/Inspector/Images/resourcePlainIcon.png
new file mode 100644
index 0000000..0ed37b6
--- /dev/null
+++ b/resources/Inspector/Images/resourcePlainIcon.png
Binary files differ
diff --git a/resources/Inspector/Images/resourcePlainIconSmall.png b/resources/Inspector/Images/resourcePlainIconSmall.png
new file mode 100644
index 0000000..0fa967d
--- /dev/null
+++ b/resources/Inspector/Images/resourcePlainIconSmall.png
Binary files differ
diff --git a/resources/Inspector/Images/resourcesIcon.png b/resources/Inspector/Images/resourcesIcon.png
new file mode 100644
index 0000000..982424d
--- /dev/null
+++ b/resources/Inspector/Images/resourcesIcon.png
Binary files differ
diff --git a/resources/Inspector/Images/resourcesSizeGraphIcon.png b/resources/Inspector/Images/resourcesSizeGraphIcon.png
new file mode 100644
index 0000000..e60dbe5
--- /dev/null
+++ b/resources/Inspector/Images/resourcesSizeGraphIcon.png
Binary files differ
diff --git a/resources/Inspector/Images/resourcesTimeGraphIcon.png b/resources/Inspector/Images/resourcesTimeGraphIcon.png
new file mode 100644
index 0000000..c6953e9
--- /dev/null
+++ b/resources/Inspector/Images/resourcesTimeGraphIcon.png
Binary files differ
diff --git a/resources/Inspector/Images/scriptsIcon.png b/resources/Inspector/Images/scriptsIcon.png
new file mode 100644
index 0000000..213b31e
--- /dev/null
+++ b/resources/Inspector/Images/scriptsIcon.png
Binary files differ
diff --git a/resources/Inspector/Images/segment.png b/resources/Inspector/Images/segment.png
new file mode 100644
index 0000000..759266e
--- /dev/null
+++ b/resources/Inspector/Images/segment.png
Binary files differ
diff --git a/resources/Inspector/Images/segmentEnd.png b/resources/Inspector/Images/segmentEnd.png
new file mode 100644
index 0000000..72672ff
--- /dev/null
+++ b/resources/Inspector/Images/segmentEnd.png
Binary files differ
diff --git a/resources/Inspector/Images/segmentHover.png b/resources/Inspector/Images/segmentHover.png
new file mode 100644
index 0000000..c5017f4
--- /dev/null
+++ b/resources/Inspector/Images/segmentHover.png
Binary files differ
diff --git a/resources/Inspector/Images/segmentHoverEnd.png b/resources/Inspector/Images/segmentHoverEnd.png
new file mode 100644
index 0000000..d51363d
--- /dev/null
+++ b/resources/Inspector/Images/segmentHoverEnd.png
Binary files differ
diff --git a/resources/Inspector/Images/segmentSelected.png b/resources/Inspector/Images/segmentSelected.png
new file mode 100644
index 0000000..c92f584
--- /dev/null
+++ b/resources/Inspector/Images/segmentSelected.png
Binary files differ
diff --git a/resources/Inspector/Images/segmentSelectedEnd.png b/resources/Inspector/Images/segmentSelectedEnd.png
new file mode 100644
index 0000000..be5e085
--- /dev/null
+++ b/resources/Inspector/Images/segmentSelectedEnd.png
Binary files differ
diff --git a/resources/Inspector/Images/splitviewDimple.png b/resources/Inspector/Images/splitviewDimple.png
new file mode 100644
index 0000000..584ffd4
--- /dev/null
+++ b/resources/Inspector/Images/splitviewDimple.png
Binary files differ
diff --git a/resources/Inspector/Images/splitviewDividerBackground.png b/resources/Inspector/Images/splitviewDividerBackground.png
new file mode 100644
index 0000000..1120a7f
--- /dev/null
+++ b/resources/Inspector/Images/splitviewDividerBackground.png
Binary files differ
diff --git a/resources/Inspector/Images/statusbarBackground.png b/resources/Inspector/Images/statusbarBackground.png
new file mode 100644
index 0000000..b466a49
--- /dev/null
+++ b/resources/Inspector/Images/statusbarBackground.png
Binary files differ
diff --git a/resources/Inspector/Images/statusbarBottomBackground.png b/resources/Inspector/Images/statusbarBottomBackground.png
new file mode 100644
index 0000000..fb5c9e4
--- /dev/null
+++ b/resources/Inspector/Images/statusbarBottomBackground.png
Binary files differ
diff --git a/resources/Inspector/Images/statusbarButtons.png b/resources/Inspector/Images/statusbarButtons.png
new file mode 100644
index 0000000..e8090cb
--- /dev/null
+++ b/resources/Inspector/Images/statusbarButtons.png
Binary files differ
diff --git a/resources/Inspector/Images/statusbarMenuButton.png b/resources/Inspector/Images/statusbarMenuButton.png
new file mode 100644
index 0000000..9b3abdd
--- /dev/null
+++ b/resources/Inspector/Images/statusbarMenuButton.png
Binary files differ
diff --git a/resources/Inspector/Images/statusbarMenuButtonSelected.png b/resources/Inspector/Images/statusbarMenuButtonSelected.png
new file mode 100644
index 0000000..8189c43
--- /dev/null
+++ b/resources/Inspector/Images/statusbarMenuButtonSelected.png
Binary files differ
diff --git a/resources/Inspector/Images/statusbarResizerHorizontal.png b/resources/Inspector/Images/statusbarResizerHorizontal.png
new file mode 100644
index 0000000..56deeab
--- /dev/null
+++ b/resources/Inspector/Images/statusbarResizerHorizontal.png
Binary files differ
diff --git a/resources/Inspector/Images/statusbarResizerVertical.png b/resources/Inspector/Images/statusbarResizerVertical.png
new file mode 100644
index 0000000..7fc1452
--- /dev/null
+++ b/resources/Inspector/Images/statusbarResizerVertical.png
Binary files differ
diff --git a/resources/Inspector/Images/timelinePillBlue.png b/resources/Inspector/Images/timelinePillBlue.png
new file mode 100644
index 0000000..c897faa
--- /dev/null
+++ b/resources/Inspector/Images/timelinePillBlue.png
Binary files differ
diff --git a/resources/Inspector/Images/timelinePillGray.png b/resources/Inspector/Images/timelinePillGray.png
new file mode 100644
index 0000000..2128896
--- /dev/null
+++ b/resources/Inspector/Images/timelinePillGray.png
Binary files differ
diff --git a/resources/Inspector/Images/timelinePillGreen.png b/resources/Inspector/Images/timelinePillGreen.png
new file mode 100644
index 0000000..9b66125
--- /dev/null
+++ b/resources/Inspector/Images/timelinePillGreen.png
Binary files differ
diff --git a/resources/Inspector/Images/timelinePillOrange.png b/resources/Inspector/Images/timelinePillOrange.png
new file mode 100644
index 0000000..dd944fb
--- /dev/null
+++ b/resources/Inspector/Images/timelinePillOrange.png
Binary files differ
diff --git a/resources/Inspector/Images/timelinePillPurple.png b/resources/Inspector/Images/timelinePillPurple.png
new file mode 100644
index 0000000..21b96f7
--- /dev/null
+++ b/resources/Inspector/Images/timelinePillPurple.png
Binary files differ
diff --git a/resources/Inspector/Images/timelinePillRed.png b/resources/Inspector/Images/timelinePillRed.png
new file mode 100644
index 0000000..f5e213b
--- /dev/null
+++ b/resources/Inspector/Images/timelinePillRed.png
Binary files differ
diff --git a/resources/Inspector/Images/timelinePillYellow.png b/resources/Inspector/Images/timelinePillYellow.png
new file mode 100644
index 0000000..ae2a5a2
--- /dev/null
+++ b/resources/Inspector/Images/timelinePillYellow.png
Binary files differ
diff --git a/resources/Inspector/Images/tipBalloon.png b/resources/Inspector/Images/tipBalloon.png
new file mode 100644
index 0000000..4cdf738
--- /dev/null
+++ b/resources/Inspector/Images/tipBalloon.png
Binary files differ
diff --git a/resources/Inspector/Images/tipBalloonBottom.png b/resources/Inspector/Images/tipBalloonBottom.png
new file mode 100644
index 0000000..3317a5a
--- /dev/null
+++ b/resources/Inspector/Images/tipBalloonBottom.png
Binary files differ
diff --git a/resources/Inspector/Images/tipIcon.png b/resources/Inspector/Images/tipIcon.png
new file mode 100644
index 0000000..8ca6124
--- /dev/null
+++ b/resources/Inspector/Images/tipIcon.png
Binary files differ
diff --git a/resources/Inspector/Images/tipIconPressed.png b/resources/Inspector/Images/tipIconPressed.png
new file mode 100644
index 0000000..443e410
--- /dev/null
+++ b/resources/Inspector/Images/tipIconPressed.png
Binary files differ
diff --git a/resources/Inspector/Images/toolbarItemSelected.png b/resources/Inspector/Images/toolbarItemSelected.png
new file mode 100644
index 0000000..bd681f1
--- /dev/null
+++ b/resources/Inspector/Images/toolbarItemSelected.png
Binary files differ
diff --git a/resources/Inspector/Images/treeDownTriangleBlack.png b/resources/Inspector/Images/treeDownTriangleBlack.png
new file mode 100644
index 0000000..0821112
--- /dev/null
+++ b/resources/Inspector/Images/treeDownTriangleBlack.png
Binary files differ
diff --git a/resources/Inspector/Images/treeDownTriangleWhite.png b/resources/Inspector/Images/treeDownTriangleWhite.png
new file mode 100644
index 0000000..1667b51
--- /dev/null
+++ b/resources/Inspector/Images/treeDownTriangleWhite.png
Binary files differ
diff --git a/resources/Inspector/Images/treeRightTriangleBlack.png b/resources/Inspector/Images/treeRightTriangleBlack.png
new file mode 100644
index 0000000..90de820
--- /dev/null
+++ b/resources/Inspector/Images/treeRightTriangleBlack.png
Binary files differ
diff --git a/resources/Inspector/Images/treeRightTriangleWhite.png b/resources/Inspector/Images/treeRightTriangleWhite.png
new file mode 100644
index 0000000..2b6a82f
--- /dev/null
+++ b/resources/Inspector/Images/treeRightTriangleWhite.png
Binary files differ
diff --git a/resources/Inspector/Images/userInputIcon.png b/resources/Inspector/Images/userInputIcon.png
new file mode 100644
index 0000000..325023f
--- /dev/null
+++ b/resources/Inspector/Images/userInputIcon.png
Binary files differ
diff --git a/resources/Inspector/Images/userInputPreviousIcon.png b/resources/Inspector/Images/userInputPreviousIcon.png
new file mode 100644
index 0000000..068d572
--- /dev/null
+++ b/resources/Inspector/Images/userInputPreviousIcon.png
Binary files differ
diff --git a/resources/Inspector/Images/warningIcon.png b/resources/Inspector/Images/warningIcon.png
new file mode 100644
index 0000000..d5e4c82
--- /dev/null
+++ b/resources/Inspector/Images/warningIcon.png
Binary files differ
diff --git a/resources/Inspector/Images/warningMediumIcon.png b/resources/Inspector/Images/warningMediumIcon.png
new file mode 100644
index 0000000..291e111
--- /dev/null
+++ b/resources/Inspector/Images/warningMediumIcon.png
Binary files differ
diff --git a/resources/Inspector/Images/warningsErrors.png b/resources/Inspector/Images/warningsErrors.png
new file mode 100644
index 0000000..878b593
--- /dev/null
+++ b/resources/Inspector/Images/warningsErrors.png
Binary files differ
diff --git a/resources/Inspector/MetricsSidebarPane.js b/resources/Inspector/MetricsSidebarPane.js
new file mode 100644
index 0000000..a22a000
--- /dev/null
+++ b/resources/Inspector/MetricsSidebarPane.js
@@ -0,0 +1,195 @@
+/*
+ * 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.
+ */
+
+WebInspector.MetricsSidebarPane = function()
+{
+    WebInspector.SidebarPane.call(this, WebInspector.UIString("Metrics"));
+}
+
+WebInspector.MetricsSidebarPane.prototype = {
+    update: function(node)
+    {
+        var body = this.bodyElement;
+
+        body.removeChildren();
+
+        if (node)
+            this.node = node;
+        else
+            node = this.node;
+
+        if (!node || !node.ownerDocument.defaultView)
+            return;
+
+        var style;
+        if (node.nodeType === Node.ELEMENT_NODE)
+            style = node.ownerDocument.defaultView.getComputedStyle(node);
+        if (!style)
+            return;
+
+        var metricsElement = document.createElement("div");
+        metricsElement.className = "metrics";
+
+        function createBoxPartElement(style, name, side, suffix)
+        {
+            var propertyName = (name !== "position" ? name + "-" : "") + side + suffix;
+            var value = style.getPropertyValue(propertyName);
+            if (value === "" || (name !== "position" && value === "0px"))
+                value = "\u2012";
+            else if (name === "position" && value === "auto")
+                value = "\u2012";
+            value = value.replace(/px$/, "");
+
+            var element = document.createElement("div");
+            element.className = side;
+            element.textContent = value;
+            element.addEventListener("dblclick", this.startEditing.bind(this, element, name, propertyName), false);
+            return element;
+        }
+
+        // Display types for which margin is ignored.
+        var noMarginDisplayType = {
+            "table-cell": true,
+            "table-column": true,
+            "table-column-group": true,
+            "table-footer-group": true,
+            "table-header-group": true,
+            "table-row": true,
+            "table-row-group": true
+        };
+
+        // Display types for which padding is ignored.
+        var noPaddingDisplayType = {
+            "table-column": true,
+            "table-column-group": true,
+            "table-footer-group": true,
+            "table-header-group": true,
+            "table-row": true,
+            "table-row-group": true
+        };
+
+        // Position types for which top, left, bottom and right are ignored.
+        var noPositionType = {
+            "static": true
+        };
+
+        var boxes = ["content", "padding", "border", "margin", "position"];
+        var boxLabels = [WebInspector.UIString("content"), WebInspector.UIString("padding"), WebInspector.UIString("border"), WebInspector.UIString("margin"), WebInspector.UIString("position")];
+        var previousBox;
+        for (var i = 0; i < boxes.length; ++i) {
+            var name = boxes[i];
+
+            if (name === "margin" && noMarginDisplayType[style.display])
+                continue;
+            if (name === "padding" && noPaddingDisplayType[style.display])
+                continue;
+            if (name === "position" && noPositionType[style.position])
+                continue;
+
+            var boxElement = document.createElement("div");
+            boxElement.className = name;
+
+            if (name === "content") {
+                var width = style.width.replace(/px$/, "");
+                var widthElement = document.createElement("span");
+                widthElement.textContent = width;
+                widthElement.addEventListener("dblclick", this.startEditing.bind(this, widthElement, "width", "width"), false);
+
+                var height = style.height.replace(/px$/, "");
+                var heightElement = document.createElement("span");
+                heightElement.textContent = height;
+                heightElement.addEventListener("dblclick", this.startEditing.bind(this, heightElement, "height", "height"), false);
+
+                boxElement.appendChild(widthElement);
+                boxElement.appendChild(document.createTextNode(" \u00D7 "));
+                boxElement.appendChild(heightElement);
+            } else {
+                var suffix = (name === "border" ? "-width" : "");
+
+                var labelElement = document.createElement("div");
+                labelElement.className = "label";
+                labelElement.textContent = boxLabels[i];
+                boxElement.appendChild(labelElement);
+
+                boxElement.appendChild(createBoxPartElement.call(this, style, name, "top", suffix));
+                boxElement.appendChild(document.createElement("br"));
+                boxElement.appendChild(createBoxPartElement.call(this, style, name, "left", suffix));
+
+                if (previousBox)
+                    boxElement.appendChild(previousBox);
+
+                boxElement.appendChild(createBoxPartElement.call(this, style, name, "right", suffix));
+                boxElement.appendChild(document.createElement("br"));
+                boxElement.appendChild(createBoxPartElement.call(this, style, name, "bottom", suffix));
+            }
+
+            previousBox = boxElement;
+        }
+
+        metricsElement.appendChild(previousBox);
+        body.appendChild(metricsElement);
+    },
+
+    startEditing: function(targetElement, box, styleProperty)
+    {
+        if (WebInspector.isBeingEdited(targetElement))
+            return;
+
+        var context = { box: box, styleProperty: styleProperty };
+
+        WebInspector.startEditing(targetElement, this.editingCommitted.bind(this), this.editingCancelled.bind(this), context);
+    },
+
+    editingCancelled: function(element, context)
+    {
+        this.update();
+    },
+
+    editingCommitted: function(element, userInput, previousContent, context)
+    {
+        if (userInput === previousContent)
+            return this.editingCancelled(element, context); // nothing changed, so cancel
+
+        if (context.box !== "position" && (!userInput || userInput === "\u2012"))
+            userInput = "0px";
+        else if (context.box === "position" && (!userInput || userInput === "\u2012"))
+            userInput = "auto";
+
+        // Append a "px" unit if the user input was just a number.
+        if (/^\d+$/.test(userInput))
+            userInput += "px";
+
+        this.node.style.setProperty(context.styleProperty, userInput, "");
+
+        this.dispatchEventToListeners("metrics edited");
+
+        this.update();
+    }
+}
+
+WebInspector.MetricsSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype;
diff --git a/resources/Inspector/Panel.js b/resources/Inspector/Panel.js
new file mode 100644
index 0000000..5046f6b
--- /dev/null
+++ b/resources/Inspector/Panel.js
@@ -0,0 +1,273 @@
+/*
+ * 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.Panel = function()
+{
+    WebInspector.View.call(this);
+
+    this.element.addStyleClass("panel");
+}
+
+WebInspector.Panel.prototype = {
+    get toolbarItem()
+    {
+        if (this._toolbarItem)
+            return this._toolbarItem;
+
+        // Sample toolbar item as markup:
+        // <button class="toolbar-item resources toggleable">
+        // <div class="toolbar-icon"></div>
+        // <div class="toolbar-label">Resources</div>
+        // </button>
+
+        this._toolbarItem = document.createElement("button");
+        this._toolbarItem.className = "toolbar-item toggleable";
+        this._toolbarItem.panel = this;
+
+        if ("toolbarItemClass" in this)
+            this._toolbarItem.addStyleClass(this.toolbarItemClass);
+
+        var iconElement = document.createElement("div");
+        iconElement.className = "toolbar-icon";
+        this._toolbarItem.appendChild(iconElement);
+
+        if ("toolbarItemLabel" in this) {
+            var labelElement = document.createElement("div");
+            labelElement.className = "toolbar-label";
+            labelElement.textContent = this.toolbarItemLabel;
+            this._toolbarItem.appendChild(labelElement);
+        }
+
+        return this._toolbarItem;
+    },
+
+    show: function()
+    {
+        WebInspector.View.prototype.show.call(this);
+
+        var statusBarItems = this.statusBarItems;
+        if (statusBarItems) {
+            this._statusBarItemContainer = document.createElement("div");
+            for (var i = 0; i < statusBarItems.length; ++i)
+                this._statusBarItemContainer.appendChild(statusBarItems[i]);
+            document.getElementById("main-status-bar").appendChild(this._statusBarItemContainer);
+        }
+
+        if ("_toolbarItem" in this)
+            this._toolbarItem.addStyleClass("toggled-on");
+
+        WebInspector.currentFocusElement = document.getElementById("main-panels");
+    },
+
+    hide: function()
+    {
+        WebInspector.View.prototype.hide.call(this);
+
+        if (this._statusBarItemContainer && this._statusBarItemContainer.parentNode)
+            this._statusBarItemContainer.parentNode.removeChild(this._statusBarItemContainer);
+        delete this._statusBarItemContainer;
+        if ("_toolbarItem" in this)
+            this._toolbarItem.removeStyleClass("toggled-on");
+    },
+
+    attach: function()
+    {
+        if (!this.element.parentNode)
+            document.getElementById("main-panels").appendChild(this.element);
+    },
+
+    searchCanceled: function(startingNewSearch)
+    {
+        if (this._searchResults) {
+            for (var i = 0; i < this._searchResults.length; ++i) {
+                var view = this._searchResults[i];
+                if (view.searchCanceled)
+                    view.searchCanceled();
+                delete view.currentQuery;
+            }
+        }
+
+        WebInspector.updateSearchMatchesCount(0, this);
+
+        if (this._currentSearchChunkIntervalIdentifier) {
+            clearInterval(this._currentSearchChunkIntervalIdentifier);
+            delete this._currentSearchChunkIntervalIdentifier;
+        }
+
+        this._totalSearchMatches = 0;
+        this._currentSearchResultIndex = 0;
+        this._searchResults = [];
+    },
+
+    performSearch: function(query)
+    {
+        // Call searchCanceled since it will reset everything we need before doing a new search.
+        this.searchCanceled(true);
+
+        var searchableViews = this.searchableViews;
+        if (!searchableViews || !searchableViews.length)
+            return;
+
+        var parentElement = this.viewsContainerElement;
+        var visibleView = this.visibleView;
+        var sortFuction = this.searchResultsSortFunction;
+
+        var matchesCountUpdateTimeout = null;
+
+        function updateMatchesCount()
+        {
+            WebInspector.updateSearchMatchesCount(this._totalSearchMatches, this);
+            matchesCountUpdateTimeout = null;
+        }
+
+        function updateMatchesCountSoon()
+        {
+            if (matchesCountUpdateTimeout)
+                return;
+            // Update the matches count every half-second so it doesn't feel twitchy.
+            matchesCountUpdateTimeout = setTimeout(updateMatchesCount.bind(this), 500);
+        }
+
+        function finishedCallback(view, searchMatches)
+        {
+            if (!searchMatches)
+                return;
+
+            this._totalSearchMatches += searchMatches;
+            this._searchResults.push(view);
+
+            if (sortFuction)
+                this._searchResults.sort(sortFuction);
+
+            if (this.searchMatchFound)
+                this.searchMatchFound(view, searchMatches);
+
+            updateMatchesCountSoon.call(this);
+
+            if (view === visibleView)
+                view.jumpToFirstSearchResult();
+        }
+
+        var i = 0;
+        var panel = this;
+        var boundFinishedCallback = finishedCallback.bind(this);
+        var chunkIntervalIdentifier = null;
+
+        // Split up the work into chunks so we don't block the
+        // UI thread while processing.
+
+        function processChunk()
+        {
+            var view = searchableViews[i];
+
+            if (++i >= searchableViews.length) {
+                if (panel._currentSearchChunkIntervalIdentifier === chunkIntervalIdentifier)
+                    delete panel._currentSearchChunkIntervalIdentifier;
+                clearInterval(chunkIntervalIdentifier);
+            }
+
+            if (!view)
+                return;
+
+            if (view.element.parentNode !== parentElement && view.element.parentNode && parentElement)
+                view.detach();
+
+            view.currentQuery = query;
+            view.performSearch(query, boundFinishedCallback);
+        }
+
+        processChunk();
+
+        chunkIntervalIdentifier = setInterval(processChunk, 25);
+        this._currentSearchChunkIntervalIdentifier = chunkIntervalIdentifier;
+    },
+
+    jumpToNextSearchResult: function()
+    {
+        if (!this.showView || !this._searchResults || !this._searchResults.length)
+            return;
+
+        var showFirstResult = false;
+
+        this._currentSearchResultIndex = this._searchResults.indexOf(this.visibleView);
+        if (this._currentSearchResultIndex === -1) {
+            this._currentSearchResultIndex = 0;
+            showFirstResult = true;
+        }
+
+        var currentView = this._searchResults[this._currentSearchResultIndex];
+
+        if (currentView.showingLastSearchResult()) {
+            if (++this._currentSearchResultIndex >= this._searchResults.length)
+                this._currentSearchResultIndex = 0;
+            currentView = this._searchResults[this._currentSearchResultIndex];
+            showFirstResult = true;
+        }
+
+        if (currentView !== this.visibleView)
+            this.showView(currentView);
+
+        if (showFirstResult)
+            currentView.jumpToFirstSearchResult();
+        else
+            currentView.jumpToNextSearchResult();
+    },
+
+    jumpToPreviousSearchResult: function()
+    {
+        if (!this.showView || !this._searchResults || !this._searchResults.length)
+            return;
+
+        var showLastResult = false;
+
+        this._currentSearchResultIndex = this._searchResults.indexOf(this.visibleView);
+        if (this._currentSearchResultIndex === -1) {
+            this._currentSearchResultIndex = 0;
+            showLastResult = true;
+        }
+
+        var currentView = this._searchResults[this._currentSearchResultIndex];
+
+        if (currentView.showingFirstSearchResult()) {
+            if (--this._currentSearchResultIndex < 0)
+                this._currentSearchResultIndex = (this._searchResults.length - 1);
+            currentView = this._searchResults[this._currentSearchResultIndex];
+            showLastResult = true;
+        }
+
+        if (currentView !== this.visibleView)
+            this.showView(currentView);
+
+        if (showLastResult)
+            currentView.jumpToLastSearchResult();
+        else
+            currentView.jumpToPreviousSearchResult();
+    }
+}
+
+WebInspector.Panel.prototype.__proto__ = WebInspector.View.prototype;
diff --git a/resources/Inspector/PropertiesSection.js b/resources/Inspector/PropertiesSection.js
new file mode 100644
index 0000000..a4b2fba
--- /dev/null
+++ b/resources/Inspector/PropertiesSection.js
@@ -0,0 +1,145 @@
+/*
+ * 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.
+ */
+
+WebInspector.PropertiesSection = function(title, subtitle)
+{
+    this.element = document.createElement("div");
+    this.element.className = "section";
+
+    this.headerElement = document.createElement("div");
+    this.headerElement.className = "header";
+
+    this.titleElement = document.createElement("div");
+    this.titleElement.className = "title";
+
+    this.subtitleElement = document.createElement("div");
+    this.subtitleElement.className = "subtitle";
+
+    this.headerElement.appendChild(this.subtitleElement);
+    this.headerElement.appendChild(this.titleElement);
+
+    this.headerElement.addEventListener("click", this.toggleExpanded.bind(this), false);
+
+    this.propertiesElement = document.createElement("ol");
+    this.propertiesElement.className = "properties";
+    this.propertiesTreeOutline = new TreeOutline(this.propertiesElement);
+    this.propertiesTreeOutline.section = this;
+
+    this.element.appendChild(this.headerElement);
+    this.element.appendChild(this.propertiesElement);
+
+    this.title = title;
+    this.subtitle = subtitle;
+    this._expanded = false;
+}
+
+WebInspector.PropertiesSection.prototype = {
+    get title()
+    {
+        return this._title;
+    },
+
+    set title(x)
+    {
+        if (this._title === x)
+            return;
+        this._title = x;
+
+        if (x instanceof Node) {
+            this.titleElement.removeChildren();
+            this.titleElement.appendChild(x);
+        } else
+          this.titleElement.textContent = x;
+    },
+
+    get subtitle()
+    {
+        return this._subtitle;
+    },
+
+    set subtitle(x)
+    {
+        if (this._subtitle === x)
+            return;
+        this._subtitle = x;
+        this.subtitleElement.innerHTML = x;
+    },
+
+    get expanded()
+    {
+        return this._expanded;
+    },
+
+    set expanded(x)
+    {
+        if (x)
+            this.expand();
+        else
+            this.collapse();
+    },
+
+    get populated()
+    {
+        return this._populated;
+    },
+
+    set populated(x)
+    {
+        this._populated = x;
+        if (!x && this.onpopulate && this._expanded) {
+            this.onpopulate(this);
+            this._populated = true;
+        }
+    },
+
+    expand: function()
+    {
+        if (this._expanded)
+            return;
+        this._expanded = true;
+        this.element.addStyleClass("expanded");
+
+        if (!this._populated && this.onpopulate) {
+            this.onpopulate(this);
+            this._populated = true;
+        }
+    },
+
+    collapse: function()
+    {
+        if (!this._expanded)
+            return;
+        this._expanded = false;
+        this.element.removeStyleClass("expanded");
+    },
+
+    toggleExpanded: function()
+    {
+        this.expanded = !this.expanded;
+    }
+}
diff --git a/resources/Inspector/PropertiesSidebarPane.js b/resources/Inspector/PropertiesSidebarPane.js
new file mode 100644
index 0000000..70db805
--- /dev/null
+++ b/resources/Inspector/PropertiesSidebarPane.js
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+WebInspector.PropertiesSidebarPane = function()
+{
+    WebInspector.SidebarPane.call(this, WebInspector.UIString("Properties"));
+}
+
+WebInspector.PropertiesSidebarPane.prototype = {
+    update: function(object)
+    {
+        var body = this.bodyElement;
+
+        body.removeChildren();
+
+        this.sections = [];
+
+        if (!object)
+            return;
+
+        for (var prototype = object; prototype; prototype = prototype.__proto__) {
+            var section = new WebInspector.ObjectPropertiesSection(prototype);
+            this.sections.push(section);
+            body.appendChild(section.element);
+        }
+    }
+}
+
+WebInspector.PropertiesSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype;
diff --git a/resources/Inspector/Resource.js b/resources/Inspector/Resource.js
new file mode 100644
index 0000000..058f232
--- /dev/null
+++ b/resources/Inspector/Resource.js
@@ -0,0 +1,625 @@
+/*
+ * 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.Resource = function(requestHeaders, url, domain, path, lastPathComponent, identifier, mainResource, cached)
+{
+    this.identifier = identifier;
+
+    this.startTime = -1;
+    this.endTime = -1;
+    this.mainResource = mainResource;
+    this.requestHeaders = requestHeaders;
+    this.url = url;
+    this.domain = domain;
+    this.path = path;
+    this.lastPathComponent = lastPathComponent;
+    this.cached = cached;
+
+    this.category = WebInspector.resourceCategories.other;
+}
+
+// Keep these in sync with WebCore::InspectorResource::Type
+WebInspector.Resource.Type = {
+    Document:   0,
+    Stylesheet: 1,
+    Image:      2,
+    Font:       3,
+    Script:     4,
+    XHR:        5,
+    Other:      6,
+
+    isTextType: function(type)
+    {
+        return (type === this.Document) || (type === this.Stylesheet) || (type === this.Script) || (type === this.XHR);
+    },
+
+    toString: function(type)
+    {
+        switch (type) {
+            case this.Document:
+                return WebInspector.UIString("document");
+            case this.Stylesheet:
+                return WebInspector.UIString("stylesheet");
+            case this.Image:
+                return WebInspector.UIString("image");
+            case this.Font:
+                return WebInspector.UIString("font");
+            case this.Script:
+                return WebInspector.UIString("script");
+            case this.XHR:
+                return WebInspector.UIString("XHR");
+            case this.Other:
+            default:
+                return WebInspector.UIString("other");
+        }
+    }
+}
+
+WebInspector.Resource.prototype = {
+    get url()
+    {
+        return this._url;
+    },
+
+    set url(x)
+    {
+        if (this._url === x)
+            return;
+
+        var oldURL = this._url;
+        this._url = x;
+
+        // FIXME: We should make the WebInspector object listen for the "url changed" event.
+        // Then resourceURLChanged can be removed.
+        WebInspector.resourceURLChanged(this, oldURL);
+
+        this.dispatchEventToListeners("url changed");
+    },
+
+    get domain()
+    {
+        return this._domain;
+    },
+
+    set domain(x)
+    {
+        if (this._domain === x)
+            return;
+        this._domain = x;
+    },
+
+    get lastPathComponent()
+    {
+        return this._lastPathComponent;
+    },
+
+    set lastPathComponent(x)
+    {
+        if (this._lastPathComponent === x)
+            return;
+        this._lastPathComponent = x;
+        this._lastPathComponentLowerCase = x ? x.toLowerCase() : null;
+    },
+
+    get displayName()
+    {
+        var title = this.lastPathComponent;
+        if (!title)
+            title = this.displayDomain;
+        if (!title && this.url)
+            title = this.url.trimURL(WebInspector.mainResource ? WebInspector.mainResource.domain : "");
+        if (title === "/")
+            title = this.url;
+        return title;
+    },
+
+    get displayDomain()
+    {
+        // WebInspector.Database calls this, so don't access more than this.domain.
+        if (this.domain && (!WebInspector.mainResource || (WebInspector.mainResource && this.domain !== WebInspector.mainResource.domain)))
+            return this.domain;
+        return "";
+    },
+
+    get startTime()
+    {
+        return this._startTime || -1;
+    },
+
+    set startTime(x)
+    {
+        if (this._startTime === x)
+            return;
+
+        this._startTime = x;
+
+        if (WebInspector.panels.resources)
+            WebInspector.panels.resources.refreshResource(this);
+    },
+
+    get responseReceivedTime()
+    {
+        return this._responseReceivedTime || -1;
+    },
+
+    set responseReceivedTime(x)
+    {
+        if (this._responseReceivedTime === x)
+            return;
+
+        this._responseReceivedTime = x;
+
+        if (WebInspector.panels.resources)
+            WebInspector.panels.resources.refreshResource(this);
+    },
+
+    get endTime()
+    {
+        return this._endTime || -1;
+    },
+
+    set endTime(x)
+    {
+        if (this._endTime === x)
+            return;
+
+        this._endTime = x;
+
+        if (WebInspector.panels.resources)
+            WebInspector.panels.resources.refreshResource(this);
+    },
+
+    get duration()
+    {
+        if (this._endTime === -1 || this._startTime === -1)
+            return -1;
+        return this._endTime - this._startTime;
+    },
+
+    get latency()
+    {
+        if (this._responseReceivedTime === -1 || this._startTime === -1)
+            return -1;
+        return this._responseReceivedTime - this._startTime;
+    },
+
+    get contentLength()
+    {
+        return this._contentLength || 0;
+    },
+
+    set contentLength(x)
+    {
+        if (this._contentLength === x)
+            return;
+
+        this._contentLength = x;
+
+        if (WebInspector.panels.resources)
+            WebInspector.panels.resources.refreshResource(this);
+    },
+
+    get expectedContentLength()
+    {
+        return this._expectedContentLength || 0;
+    },
+
+    set expectedContentLength(x)
+    {
+        if (this._expectedContentLength === x)
+            return;
+        this._expectedContentLength = x;
+    },
+
+    get finished()
+    {
+        return this._finished;
+    },
+
+    set finished(x)
+    {
+        if (this._finished === x)
+            return;
+
+        this._finished = x;
+
+        if (x) {
+            this._checkTips();
+            this._checkWarnings();
+            this.dispatchEventToListeners("finished");
+        }
+    },
+
+    get failed()
+    {
+        return this._failed;
+    },
+
+    set failed(x)
+    {
+        this._failed = x;
+    },
+
+    get category()
+    {
+        return this._category;
+    },
+
+    set category(x)
+    {
+        if (this._category === x)
+            return;
+
+        var oldCategory = this._category;
+        if (oldCategory)
+            oldCategory.removeResource(this);
+
+        this._category = x;
+
+        if (this._category)
+            this._category.addResource(this);
+
+        if (WebInspector.panels.resources) {
+            WebInspector.panels.resources.refreshResource(this);
+            WebInspector.panels.resources.recreateViewForResourceIfNeeded(this);
+        }
+    },
+
+    get mimeType()
+    {
+        return this._mimeType;
+    },
+
+    set mimeType(x)
+    {
+        if (this._mimeType === x)
+            return;
+
+        this._mimeType = x;
+    },
+
+    get type()
+    {
+        return this._type;
+    },
+
+    set type(x)
+    {
+        if (this._type === x)
+            return;
+
+        this._type = x;
+
+        switch (x) {
+            case WebInspector.Resource.Type.Document:
+                this.category = WebInspector.resourceCategories.documents;
+                break;
+            case WebInspector.Resource.Type.Stylesheet:
+                this.category = WebInspector.resourceCategories.stylesheets;
+                break;
+            case WebInspector.Resource.Type.Script:
+                this.category = WebInspector.resourceCategories.scripts;
+                break;
+            case WebInspector.Resource.Type.Image:
+                this.category = WebInspector.resourceCategories.images;
+                break;
+            case WebInspector.Resource.Type.Font:
+                this.category = WebInspector.resourceCategories.fonts;
+                break;
+            case WebInspector.Resource.Type.XHR:
+                this.category = WebInspector.resourceCategories.xhr;
+                break;
+            case WebInspector.Resource.Type.Other:
+            default:
+                this.category = WebInspector.resourceCategories.other;
+                break;
+        }
+    },
+
+    get documentNode() {
+        if ("identifier" in this)
+            return InspectorController.getResourceDocumentNode(this.identifier);
+        return null;
+    },
+
+    get requestHeaders()
+    {
+        if (this._requestHeaders === undefined)
+            this._requestHeaders = {};
+        return this._requestHeaders;
+    },
+
+    set requestHeaders(x)
+    {
+        if (this._requestHeaders === x)
+            return;
+
+        this._requestHeaders = x;
+        delete this._sortedRequestHeaders;
+
+        this.dispatchEventToListeners("requestHeaders changed");
+    },
+
+    get sortedRequestHeaders()
+    {
+        if (this._sortedRequestHeaders !== undefined)
+            return this._sortedRequestHeaders;
+
+        this._sortedRequestHeaders = [];
+        for (var key in this.requestHeaders)
+            this._sortedRequestHeaders.push({header: key, value: this.requestHeaders[key]});
+        this._sortedRequestHeaders.sort(function(a,b) { return a.header.localeCompare(b.header) });
+
+        return this._sortedRequestHeaders;
+    },
+
+    get responseHeaders()
+    {
+        if (this._responseHeaders === undefined)
+            this._responseHeaders = {};
+        return this._responseHeaders;
+    },
+
+    set responseHeaders(x)
+    {
+        if (this._responseHeaders === x)
+            return;
+
+        this._responseHeaders = x;
+        delete this._sortedResponseHeaders;
+
+        this.dispatchEventToListeners("responseHeaders changed");
+    },
+
+    get sortedResponseHeaders()
+    {
+        if (this._sortedResponseHeaders !== undefined)
+            return this._sortedResponseHeaders;
+
+        this._sortedResponseHeaders = [];
+        for (var key in this.responseHeaders)
+            this._sortedResponseHeaders.push({header: key, value: this.responseHeaders[key]});
+        this._sortedResponseHeaders.sort(function(a,b) { return a.header.localeCompare(b.header) });
+
+        return this._sortedResponseHeaders;
+    },
+
+    get scripts()
+    {
+        if (!("_scripts" in this))
+            this._scripts = [];
+        return this._scripts;
+    },
+
+    addScript: function(script)
+    {
+        if (!script)
+            return;
+        this.scripts.unshift(script);
+        script.resource = this;
+    },
+
+    removeAllScripts: function()
+    {
+        if (!this._scripts)
+            return;
+
+        for (var i = 0; i < this._scripts.length; ++i) {
+            if (this._scripts[i].resource === this)
+                delete this._scripts[i].resource;
+        }
+
+        delete this._scripts;
+    },
+
+    removeScript: function(script)
+    {
+        if (!script)
+            return;
+
+        if (script.resource === this)
+            delete script.resource;
+
+        if (!this._scripts)
+            return;
+
+        this._scripts.remove(script);
+    },
+
+    get errors()
+    {
+        return this._errors || 0;
+    },
+
+    set errors(x)
+    {
+        this._errors = x;
+    },
+
+    get warnings()
+    {
+        return this._warnings || 0;
+    },
+
+    set warnings(x)
+    {
+        this._warnings = x;
+    },
+
+    get tips()
+    {
+        if (!("_tips" in this))
+            this._tips = {};
+        return this._tips;
+    },
+
+    _addTip: function(tip)
+    {
+        if (tip.id in this.tips)
+            return;
+
+        this.tips[tip.id] = tip;
+
+        // FIXME: Re-enable this code once we have a scope bar in the Console.
+        // Otherwise, we flood the Console with too many tips.
+        /*
+        var msg = new WebInspector.ConsoleMessage(WebInspector.ConsoleMessage.MessageSource.Other,
+            WebInspector.ConsoleMessage.MessageLevel.Tip, -1, this.url, null, 1, tip.message);
+        WebInspector.console.addMessage(msg);
+        */
+    },
+
+    _checkTips: function()
+    {
+        for (var tip in WebInspector.Tips)
+            this._checkTip(WebInspector.Tips[tip]);
+    },
+
+    _checkTip: function(tip)
+    {
+        var addTip = false;
+        switch (tip.id) {
+            case WebInspector.Tips.ResourceNotCompressed.id:
+                addTip = this._shouldCompress();
+                break;
+        }
+
+        if (addTip)
+            this._addTip(tip);
+    },
+
+    _shouldCompress: function()
+    {
+        return WebInspector.Resource.Type.isTextType(this.type)
+            && this.domain
+            && !("Content-Encoding" in this.responseHeaders)
+            && this.contentLength !== undefined
+            && this.contentLength >= 512;
+    },
+
+    _mimeTypeIsConsistentWithType: function()
+    {
+        if (typeof this.type === "undefined"
+         || this.type === WebInspector.Resource.Type.Other
+         || this.type === WebInspector.Resource.Type.XHR)
+            return true;
+
+        if (this.mimeType in WebInspector.MIMETypes)
+            return this.type in WebInspector.MIMETypes[this.mimeType];
+
+        return true;
+    },
+
+    _checkWarnings: function()
+    {
+        for (var warning in WebInspector.Warnings)
+            this._checkWarning(WebInspector.Warnings[warning]);
+    },
+
+    _checkWarning: function(warning)
+    {
+        var addWarning = false;
+        var msg;
+        switch (warning.id) {
+            case WebInspector.Warnings.IncorrectMIMEType.id:
+                if (!this._mimeTypeIsConsistentWithType())
+                    msg = new WebInspector.ConsoleMessage(WebInspector.ConsoleMessage.MessageSource.Other,
+                        WebInspector.ConsoleMessage.MessageLevel.Warning, -1, this.url, null, 1,
+                        String.sprintf(WebInspector.Warnings.IncorrectMIMEType.message,
+                        WebInspector.Resource.Type.toString(this.type), this.mimeType));
+                break;
+        }
+
+        if (msg)
+            WebInspector.console.addMessage(msg);
+    }
+}
+
+WebInspector.Resource.prototype.__proto__ = WebInspector.Object.prototype;
+
+WebInspector.Resource.CompareByStartTime = function(a, b)
+{
+    if (a.startTime < b.startTime)
+        return -1;
+    if (a.startTime > b.startTime)
+        return 1;
+    return 0;
+}
+
+WebInspector.Resource.CompareByResponseReceivedTime = function(a, b)
+{
+    if (a.responseReceivedTime === -1 && b.responseReceivedTime !== -1)
+        return 1;
+    if (a.responseReceivedTime !== -1 && b.responseReceivedTime === -1)
+        return -1;
+    if (a.responseReceivedTime < b.responseReceivedTime)
+        return -1;
+    if (a.responseReceivedTime > b.responseReceivedTime)
+        return 1;
+    return 0;
+}
+
+WebInspector.Resource.CompareByEndTime = function(a, b)
+{
+    if (a.endTime === -1 && b.endTime !== -1)
+        return 1;
+    if (a.endTime !== -1 && b.endTime === -1)
+        return -1;
+    if (a.endTime < b.endTime)
+        return -1;
+    if (a.endTime > b.endTime)
+        return 1;
+    return 0;
+}
+
+WebInspector.Resource.CompareByDuration = function(a, b)
+{
+    if (a.duration < b.duration)
+        return -1;
+    if (a.duration > b.duration)
+        return 1;
+    return 0;
+}
+
+WebInspector.Resource.CompareByLatency = function(a, b)
+{
+    if (a.latency < b.latency)
+        return -1;
+    if (a.latency > b.latency)
+        return 1;
+    return 0;
+}
+
+WebInspector.Resource.CompareBySize = function(a, b)
+{
+    if (a.contentLength < b.contentLength)
+        return -1;
+    if (a.contentLength > b.contentLength)
+        return 1;
+    return 0;
+}
diff --git a/resources/Inspector/ResourceCategory.js b/resources/Inspector/ResourceCategory.js
new file mode 100644
index 0000000..fc508d0
--- /dev/null
+++ b/resources/Inspector/ResourceCategory.js
@@ -0,0 +1,68 @@
+/*
+ * 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.ResourceCategory = function(title, name)
+{
+    this.name = name;
+    this.title = title;
+    this.resources = [];
+}
+
+WebInspector.ResourceCategory.prototype = {
+    toString: function()
+    {
+        return this.title;
+    },
+
+    addResource: function(resource)
+    {
+        var a = resource;
+        var resourcesLength = this.resources.length;
+        for (var i = 0; i < resourcesLength; ++i) {
+            var b = this.resources[i];
+            if (a._lastPathComponentLowerCase && b._lastPathComponentLowerCase)
+                if (a._lastPathComponentLowerCase < b._lastPathComponentLowerCase)
+                    break;
+            else if (a.name && b.name)
+                if (a.name < b.name)
+                    break;
+        }
+
+        this.resources.splice(i, 0, resource);
+    },
+
+    removeResource: function(resource)
+    {
+        this.resources.remove(resource, true);
+    },
+
+    removeAllResources: function(resource)
+    {
+        this.resources = [];
+    }
+}
diff --git a/resources/Inspector/ResourceView.js b/resources/Inspector/ResourceView.js
new file mode 100644
index 0000000..b480362
--- /dev/null
+++ b/resources/Inspector/ResourceView.js
@@ -0,0 +1,140 @@
+/*
+ * 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.ResourceView = function(resource)
+{
+    WebInspector.View.call(this);
+
+    this.element.addStyleClass("resource-view");
+
+    this.resource = resource;
+
+    this.headersElement = document.createElement("div");
+    this.headersElement.className = "resource-view-headers";
+    this.element.appendChild(this.headersElement);
+
+    this.contentElement = document.createElement("div");
+    this.contentElement.className = "resource-view-content";
+    this.element.appendChild(this.contentElement);
+
+    this.headersListElement = document.createElement("ol");
+    this.headersListElement.className = "outline-disclosure";
+    this.headersElement.appendChild(this.headersListElement);
+
+    this.headersTreeOutline = new TreeOutline(this.headersListElement);
+    this.headersTreeOutline.expandTreeElementsWhenArrowing = true;
+
+    this.urlTreeElement = new TreeElement("", null, false);
+    this.urlTreeElement.selectable = false;
+    this.headersTreeOutline.appendChild(this.urlTreeElement);
+
+    this.requestHeadersTreeElement = new TreeElement("", null, true);
+    this.requestHeadersTreeElement.expanded = false;
+    this.requestHeadersTreeElement.selectable = false;
+    this.headersTreeOutline.appendChild(this.requestHeadersTreeElement);
+
+    this.responseHeadersTreeElement = new TreeElement("", null, true);
+    this.responseHeadersTreeElement.expanded = false;
+    this.responseHeadersTreeElement.selectable = false;
+    this.headersTreeOutline.appendChild(this.responseHeadersTreeElement);
+
+    this.headersVisible = true;
+
+    resource.addEventListener("url changed", this._refreshURL, this);
+    resource.addEventListener("requestHeaders changed", this._refreshRequestHeaders, this);
+    resource.addEventListener("responseHeaders changed", this._refreshResponseHeaders, this);
+
+    this._refreshURL();
+    this._refreshRequestHeaders();
+    this._refreshResponseHeaders();
+}
+
+WebInspector.ResourceView.prototype = {
+    get headersVisible()
+    {
+        return this._headersVisible;
+    },
+
+    set headersVisible(x)
+    {
+        if (x === this._headersVisible)
+            return;
+
+        this._headersVisible = x;
+
+        if (x)
+            this.element.addStyleClass("headers-visible");
+        else
+            this.element.removeStyleClass("headers-visible");
+    },
+
+    attach: function()
+    {
+        if (!this.element.parentNode) {
+            var parentElement = (document.getElementById("resource-views") || document.getElementById("script-resource-views"));
+            if (parentElement)
+                parentElement.appendChild(this.element);
+        }
+    },
+
+    _refreshURL: function()
+    {
+        this.urlTreeElement.title = this.resource.url.escapeHTML();
+    },
+
+    _refreshRequestHeaders: function()
+    {
+        this._refreshHeaders(WebInspector.UIString("Request Headers"), this.resource.sortedRequestHeaders, this.requestHeadersTreeElement);
+    },
+
+    _refreshResponseHeaders: function()
+    {
+        this._refreshHeaders(WebInspector.UIString("Response Headers"), this.resource.sortedResponseHeaders, this.responseHeadersTreeElement);
+    },
+
+    _refreshHeaders: function(title, headers, headersTreeElement)
+    {
+        headersTreeElement.removeChildren();
+
+        var length = headers.length;
+        headersTreeElement.title = title.escapeHTML() + "<span class=\"header-count\">" + WebInspector.UIString(" (%d)", length) + "</span>";
+        headersTreeElement.hidden = !length;
+
+        var length = headers.length;
+        for (var i = 0; i < length; ++i) {
+            var title = "<div class=\"header-name\">" + headers[i].header.escapeHTML() + ":</div>";
+            title += "<div class=\"header-value\">" + headers[i].value.escapeHTML() + "</div>"
+
+            var headerTreeElement = new TreeElement(title, null, false);
+            headerTreeElement.selectable = false;
+            headersTreeElement.appendChild(headerTreeElement);
+        }
+    }
+}
+
+WebInspector.ResourceView.prototype.__proto__ = WebInspector.View.prototype;
diff --git a/resources/Inspector/ResourcesPanel.js b/resources/Inspector/ResourcesPanel.js
new file mode 100644
index 0000000..e02baf3
--- /dev/null
+++ b/resources/Inspector/ResourcesPanel.js
@@ -0,0 +1,1649 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc.  All rights reserved.
+ * Copyright (C) 2008 Anthony Ricaud (rik24d@gmail.com)
+ *
+ * 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.ResourcesPanel = function()
+{
+    WebInspector.Panel.call(this);
+
+    this.element.addStyleClass("resources");
+
+    this.viewsContainerElement = document.createElement("div");
+    this.viewsContainerElement.id = "resource-views";
+    this.element.appendChild(this.viewsContainerElement);
+
+    this.containerElement = document.createElement("div");
+    this.containerElement.id = "resources-container";
+    this.containerElement.addEventListener("scroll", this._updateDividersLabelBarPosition.bind(this), false);
+    this.element.appendChild(this.containerElement);
+
+    this.sidebarElement = document.createElement("div");
+    this.sidebarElement.id = "resources-sidebar";
+    this.sidebarElement.className = "sidebar";
+    this.containerElement.appendChild(this.sidebarElement);
+
+    this.sidebarResizeElement = document.createElement("div");
+    this.sidebarResizeElement.className = "sidebar-resizer-vertical";
+    this.sidebarResizeElement.addEventListener("mousedown", this._startSidebarDragging.bind(this), false);
+    this.element.appendChild(this.sidebarResizeElement);
+
+    this.containerContentElement = document.createElement("div");
+    this.containerContentElement.id = "resources-container-content";
+    this.containerElement.appendChild(this.containerContentElement);
+
+    this.summaryElement = document.createElement("div");
+    this.summaryElement.id = "resources-summary";
+    this.containerContentElement.appendChild(this.summaryElement);
+
+    this.resourcesGraphsElement = document.createElement("div");
+    this.resourcesGraphsElement.id = "resources-graphs";
+    this.containerContentElement.appendChild(this.resourcesGraphsElement);
+
+    this.dividersElement = document.createElement("div");
+    this.dividersElement.id = "resources-dividers";
+    this.containerContentElement.appendChild(this.dividersElement);
+
+    this.dividersLabelBarElement = document.createElement("div");
+    this.dividersLabelBarElement.id = "resources-dividers-label-bar";
+    this.containerContentElement.appendChild(this.dividersLabelBarElement);
+
+    this.summaryGraphElement = document.createElement("canvas");
+    this.summaryGraphElement.setAttribute("width", "450");
+    this.summaryGraphElement.setAttribute("height", "38");
+    this.summaryGraphElement.id = "resources-summary-graph";
+    this.summaryElement.appendChild(this.summaryGraphElement);
+
+    this.legendElement = document.createElement("div");
+    this.legendElement.id = "resources-graph-legend";
+    this.summaryElement.appendChild(this.legendElement);
+
+    this.sidebarTreeElement = document.createElement("ol");
+    this.sidebarTreeElement.className = "sidebar-tree";
+    this.sidebarElement.appendChild(this.sidebarTreeElement);
+
+    this.sidebarTree = new TreeOutline(this.sidebarTreeElement);
+
+    var timeGraphItem = new WebInspector.SidebarTreeElement("resources-time-graph-sidebar-item", WebInspector.UIString("Time"));
+    timeGraphItem.onselect = this._graphSelected.bind(this);
+
+    var transferTimeCalculator = new WebInspector.ResourceTransferTimeCalculator();
+    var transferDurationCalculator = new WebInspector.ResourceTransferDurationCalculator();
+
+    timeGraphItem.sortingOptions = [
+        { name: WebInspector.UIString("Sort by Start Time"), sortingFunction: WebInspector.ResourceSidebarTreeElement.CompareByAscendingStartTime, calculator: transferTimeCalculator },
+        { name: WebInspector.UIString("Sort by Response Time"), sortingFunction: WebInspector.ResourceSidebarTreeElement.CompareByAscendingResponseReceivedTime, calculator: transferTimeCalculator },
+        { name: WebInspector.UIString("Sort by End Time"), sortingFunction: WebInspector.ResourceSidebarTreeElement.CompareByAscendingEndTime, calculator: transferTimeCalculator },
+        { name: WebInspector.UIString("Sort by Duration"), sortingFunction: WebInspector.ResourceSidebarTreeElement.CompareByDescendingDuration, calculator: transferDurationCalculator },
+        { name: WebInspector.UIString("Sort by Latency"), sortingFunction: WebInspector.ResourceSidebarTreeElement.CompareByDescendingLatency, calculator: transferDurationCalculator },
+    ];
+
+    timeGraphItem.selectedSortingOptionIndex = 1;
+
+    var sizeGraphItem = new WebInspector.SidebarTreeElement("resources-size-graph-sidebar-item", WebInspector.UIString("Size"));
+    sizeGraphItem.onselect = this._graphSelected.bind(this);
+
+    var transferSizeCalculator = new WebInspector.ResourceTransferSizeCalculator();
+    sizeGraphItem.sortingOptions = [
+        { name: WebInspector.UIString("Sort by Size"), sortingFunction: WebInspector.ResourceSidebarTreeElement.CompareByDescendingSize, calculator: transferSizeCalculator },
+    ];
+
+    sizeGraphItem.selectedSortingOptionIndex = 0;
+
+    this.graphsTreeElement = new WebInspector.SidebarSectionTreeElement(WebInspector.UIString("GRAPHS"), {}, true);
+    this.sidebarTree.appendChild(this.graphsTreeElement);
+
+    this.graphsTreeElement.appendChild(timeGraphItem);
+    this.graphsTreeElement.appendChild(sizeGraphItem);
+    this.graphsTreeElement.expand();
+
+    this.resourcesTreeElement = new WebInspector.SidebarSectionTreeElement(WebInspector.UIString("RESOURCES"), {}, true);
+    this.sidebarTree.appendChild(this.resourcesTreeElement);
+
+    this.resourcesTreeElement.expand();
+
+    this.largerResourcesButton = document.createElement("button");
+    this.largerResourcesButton.id = "resources-larger-resources-status-bar-item";
+    this.largerResourcesButton.className = "status-bar-item toggled-on";
+    this.largerResourcesButton.title = WebInspector.UIString("Use small resource rows.");
+    this.largerResourcesButton.addEventListener("click", this._toggleLargerResources.bind(this), false);
+
+    this.sortingSelectElement = document.createElement("select");
+    this.sortingSelectElement.className = "status-bar-item";
+    this.sortingSelectElement.addEventListener("change", this._changeSortingFunction.bind(this), false);
+
+    this.reset();
+
+    timeGraphItem.select();
+}
+
+WebInspector.ResourcesPanel.prototype = {
+    toolbarItemClass: "resources",
+
+    get toolbarItemLabel()
+    {
+        return WebInspector.UIString("Resources");
+    },
+
+    get statusBarItems()
+    {
+        return [this.largerResourcesButton, this.sortingSelectElement];
+    },
+
+    show: function()
+    {
+        WebInspector.Panel.prototype.show.call(this);
+
+        this._updateDividersLabelBarPosition();
+        this._updateSidebarWidth();
+        this.refreshIfNeeded();
+
+        var visibleView = this.visibleView;
+        if (visibleView) {
+            visibleView.headersVisible = true;
+            visibleView.show(this.viewsContainerElement);
+        }
+
+        // Hide any views that are visible that are not this panel's current visible view.
+        // This can happen when a ResourceView is visible in the Scripts panel then switched
+        // to the this panel.
+        var resourcesLength = this._resources.length;
+        for (var i = 0; i < resourcesLength; ++i) {
+            var resource = this._resources[i];
+            var view = resource._resourcesView;
+            if (!view || view === visibleView)
+                continue;
+            view.visible = false;
+        }
+    },
+
+    resize: function()
+    {
+        this._updateGraphDividersIfNeeded();
+
+        var visibleView = this.visibleView;
+        if (visibleView && "resize" in visibleView)
+            visibleView.resize();
+    },
+
+    get searchableViews()
+    {
+        var views = [];
+
+        const visibleView = this.visibleView;
+        if (visibleView && visibleView.performSearch)
+            views.push(visibleView);
+
+        var resourcesLength = this._resources.length;
+        for (var i = 0; i < resourcesLength; ++i) {
+            var resource = this._resources[i];
+            if (!resource._resourcesTreeElement)
+                continue;
+            var resourceView = this.resourceViewForResource(resource);
+            if (!resourceView.performSearch || resourceView === visibleView)
+                continue;
+            views.push(resourceView);
+        }
+
+        return views;
+    },
+
+    get searchResultsSortFunction()
+    {
+        const resourceTreeElementSortFunction = this.sortingFunction;
+
+        function sortFuction(a, b)
+        {
+            return resourceTreeElementSortFunction(a.resource._resourcesTreeElement, b.resource._resourcesTreeElement);
+        }
+
+        return sortFuction;
+    },
+
+    searchMatchFound: function(view, matches)
+    {
+        view.resource._resourcesTreeElement.searchMatches = matches;
+    },
+
+    searchCanceled: function(startingNewSearch)
+    {
+        WebInspector.Panel.prototype.searchCanceled.call(this, startingNewSearch);
+
+        if (startingNewSearch || !this._resources)
+            return;
+
+        for (var i = 0; i < this._resources.length; ++i) {
+            var resource = this._resources[i];
+            if (resource._resourcesTreeElement)
+                resource._resourcesTreeElement.updateErrorsAndWarnings();
+        }
+    },
+
+    performSearch: function(query)
+    {
+        for (var i = 0; i < this._resources.length; ++i) {
+            var resource = this._resources[i];
+            if (resource._resourcesTreeElement)
+                resource._resourcesTreeElement.resetBubble();
+        }
+
+        WebInspector.Panel.prototype.performSearch.call(this, query);
+    },
+
+    get visibleView()
+    {
+        if (this.visibleResource)
+            return this.visibleResource._resourcesView;
+        return null;
+    },
+
+    get calculator()
+    {
+        return this._calculator;
+    },
+
+    set calculator(x)
+    {
+        if (!x || this._calculator === x)
+            return;
+
+        this._calculator = x;
+        this._calculator.reset();
+
+        this._staleResources = this._resources;
+        this.refresh();
+    },
+
+    get sortingFunction()
+    {
+        return this._sortingFunction;
+    },
+
+    set sortingFunction(x)
+    {
+        this._sortingFunction = x;
+        this._sortResourcesIfNeeded();
+    },
+
+    get needsRefresh()
+    {
+        return this._needsRefresh;
+    },
+
+    set needsRefresh(x)
+    {
+        if (this._needsRefresh === x)
+            return;
+
+        this._needsRefresh = x;
+
+        if (x) {
+            if (this.visible && !("_refreshTimeout" in this))
+                this._refreshTimeout = setTimeout(this.refresh.bind(this), 500);
+        } else {
+            if ("_refreshTimeout" in this) {
+                clearTimeout(this._refreshTimeout);
+                delete this._refreshTimeout;
+            }
+        }
+    },
+
+    refreshIfNeeded: function()
+    {
+        if (this.needsRefresh)
+            this.refresh();
+    },
+
+    refresh: function()
+    {
+        this.needsRefresh = false;
+
+        var staleResourcesLength = this._staleResources.length;
+        var boundariesChanged = false;
+
+        for (var i = 0; i < staleResourcesLength; ++i) {
+            var resource = this._staleResources[i];
+            if (!resource._resourcesTreeElement) {
+                // Create the resource tree element and graph.
+                resource._resourcesTreeElement = new WebInspector.ResourceSidebarTreeElement(resource);
+                resource._resourcesTreeElement._resourceGraph = new WebInspector.ResourceGraph(resource);
+
+                this.resourcesTreeElement.appendChild(resource._resourcesTreeElement);
+                this.resourcesGraphsElement.appendChild(resource._resourcesTreeElement._resourceGraph.graphElement);
+            }
+
+            resource._resourcesTreeElement.refresh();
+
+            if (this.calculator.updateBoundaries(resource))
+                boundariesChanged = true;
+        }
+
+        if (boundariesChanged) {
+            // The boundaries changed, so all resource graphs are stale.
+            this._staleResources = this._resources;
+            staleResourcesLength = this._staleResources.length;
+        }
+
+        for (var i = 0; i < staleResourcesLength; ++i)
+            this._staleResources[i]._resourcesTreeElement._resourceGraph.refresh(this.calculator);
+
+        this._staleResources = [];
+
+        this._updateGraphDividersIfNeeded();
+        this._sortResourcesIfNeeded();
+        this._updateSummaryGraph();
+    },
+
+    reset: function()
+    {
+        this.closeVisibleResource();
+
+        this.containerElement.scrollTop = 0;
+
+        delete this.currentQuery;
+        this.searchCanceled();
+
+        if (this._calculator)
+            this._calculator.reset();
+
+        if (this._resources) {
+            var resourcesLength = this._resources.length;
+            for (var i = 0; i < resourcesLength; ++i) {
+                var resource = this._resources[i];
+
+                resource.warnings = 0;
+                resource.errors = 0;
+
+                delete resource._resourcesTreeElement;
+                delete resource._resourcesView;
+            }
+        }
+
+        this._resources = [];
+        this._staleResources = [];
+
+        this.resourcesTreeElement.removeChildren();
+        this.viewsContainerElement.removeChildren();
+        this.resourcesGraphsElement.removeChildren();
+        this.legendElement.removeChildren();
+
+        this._updateGraphDividersIfNeeded(true);
+
+        this._drawSummaryGraph(); // draws an empty graph
+    },
+
+    addResource: function(resource)
+    {
+        this._resources.push(resource);
+        this.refreshResource(resource);
+    },
+
+    removeResource: function(resource)
+    {
+        if (this.visibleView === resource._resourcesView)
+            this.closeVisibleResource();
+
+        this._resources.remove(resource, true);
+
+        if (resource._resourcesTreeElement) {
+            this.resourcesTreeElement.removeChild(resource._resourcesTreeElement);
+            this.resourcesGraphsElement.removeChild(resource._resourcesTreeElement._resourceGraph.graphElement);
+        }
+
+        resource.warnings = 0;
+        resource.errors = 0;
+
+        delete resource._resourcesTreeElement;
+        delete resource._resourcesView;
+
+        this._adjustScrollPosition();
+    },
+
+    addMessageToResource: function(resource, msg)
+    {
+        if (!resource)
+            return;
+
+        switch (msg.level) {
+        case WebInspector.ConsoleMessage.MessageLevel.Warning:
+            resource.warnings += msg.repeatDelta;
+            break;
+        case WebInspector.ConsoleMessage.MessageLevel.Error:
+            resource.errors += msg.repeatDelta;
+            break;
+        }
+
+        if (!this.currentQuery && resource._resourcesTreeElement)
+            resource._resourcesTreeElement.updateErrorsAndWarnings();
+
+        var view = this.resourceViewForResource(resource);
+        if (view.addMessage)
+            view.addMessage(msg);
+    },
+
+    clearMessages: function()
+    {
+        var resourcesLength = this._resources.length;
+        for (var i = 0; i < resourcesLength; ++i) {
+            var resource = this._resources[i];
+            resource.warnings = 0;
+            resource.errors = 0;
+
+            if (!this.currentQuery && resource._resourcesTreeElement)
+                resource._resourcesTreeElement.updateErrorsAndWarnings();
+
+            var view = resource._resourcesView;
+            if (!view || !view.clearMessages)
+                continue;
+            view.clearMessages();
+        }
+    },
+
+    refreshResource: function(resource)
+    {
+        this._staleResources.push(resource);
+        this.needsRefresh = true;
+    },
+
+    recreateViewForResourceIfNeeded: function(resource)
+    {
+        if (!resource || !resource._resourcesView)
+            return;
+
+        var newView = this._createResourceView(resource);
+        if (newView.prototype === resource._resourcesView.prototype)
+            return;
+
+        resource.warnings = 0;
+        resource.errors = 0;
+
+        if (!this.currentQuery && resource._resourcesTreeElement)
+            resource._resourcesTreeElement.updateErrorsAndWarnings();
+
+        var oldView = resource._resourcesView;
+
+        resource._resourcesView.detach();
+        delete resource._resourcesView;
+
+        resource._resourcesView = newView;
+
+        newView.headersVisible = oldView.headersVisible;
+
+        if (oldView.visible && oldView.element.parentNode)
+            newView.show(oldView.element.parentNode);
+    },
+
+    showResource: function(resource, line)
+    {
+        if (!resource)
+            return;
+
+        this.containerElement.addStyleClass("viewing-resource");
+
+        if (this.visibleResource && this.visibleResource._resourcesView)
+            this.visibleResource._resourcesView.hide();
+
+        var view = this.resourceViewForResource(resource);
+        view.headersVisible = true;
+        view.show(this.viewsContainerElement);
+
+        if (line) {
+            if (view.revealLine)
+                view.revealLine(line);
+            if (view.highlightLine)
+                view.highlightLine(line);
+        }
+
+        if (resource._resourcesTreeElement) {
+            resource._resourcesTreeElement.reveal();
+            resource._resourcesTreeElement.select(true);
+        }
+
+        this.visibleResource = resource;
+
+        this._updateSidebarWidth();
+    },
+
+    showView: function(view)
+    {
+        if (!view)
+            return;
+        this.showResource(view.resource);
+    },
+
+    closeVisibleResource: function()
+    {
+        this.containerElement.removeStyleClass("viewing-resource");
+        this._updateDividersLabelBarPosition();
+
+        if (this.visibleResource && this.visibleResource._resourcesView)
+            this.visibleResource._resourcesView.hide();
+        delete this.visibleResource;
+
+        if (this._lastSelectedGraphTreeElement)
+            this._lastSelectedGraphTreeElement.select(true);
+
+        this._updateSidebarWidth();
+    },
+
+    resourceViewForResource: function(resource)
+    {
+        if (!resource)
+            return null;
+        if (!resource._resourcesView)
+            resource._resourcesView = this._createResourceView(resource);
+        return resource._resourcesView;
+    },
+
+    sourceFrameForResource: function(resource)
+    {
+        var view = this.resourceViewForResource(resource);
+        if (!view)
+            return null;
+
+        if (!view.setupSourceFrameIfNeeded)
+            return null;
+
+        // Setting up the source frame requires that we be attached.
+        if (!this.element.parentNode)
+            this.attach();
+
+        view.setupSourceFrameIfNeeded();
+        return view.sourceFrame;
+    },
+
+    handleKeyEvent: function(event)
+    {
+        this.sidebarTree.handleKeyEvent(event);
+    },
+
+    _makeLegendElement: function(label, value, color)
+    {
+        var legendElement = document.createElement("label");
+        legendElement.className = "resources-graph-legend-item";
+
+        if (color) {
+            var swatch = document.createElement("canvas");
+            swatch.className = "resources-graph-legend-swatch";
+            swatch.setAttribute("width", "13");
+            swatch.setAttribute("height", "24");
+
+            legendElement.appendChild(swatch);
+
+            this._drawSwatch(swatch, color);
+        }
+
+        var labelElement = document.createElement("div");
+        labelElement.className = "resources-graph-legend-label";
+        legendElement.appendChild(labelElement);
+
+        var headerElement = document.createElement("div");
+        var headerElement = document.createElement("div");
+        headerElement.className = "resources-graph-legend-header";
+        headerElement.textContent = label;
+        labelElement.appendChild(headerElement);
+
+        var valueElement = document.createElement("div");
+        valueElement.className = "resources-graph-legend-value";
+        valueElement.textContent = value;
+        labelElement.appendChild(valueElement);
+
+        return legendElement;
+    },
+
+    _sortResourcesIfNeeded: function()
+    {
+        var sortedElements = [].concat(this.resourcesTreeElement.children);
+        sortedElements.sort(this.sortingFunction);
+
+        var sortedElementsLength = sortedElements.length;
+        for (var i = 0; i < sortedElementsLength; ++i) {
+            var treeElement = sortedElements[i];
+            if (treeElement === this.resourcesTreeElement.children[i])
+                continue;
+
+            var wasSelected = treeElement.selected;
+            this.resourcesTreeElement.removeChild(treeElement);
+            this.resourcesTreeElement.insertChild(treeElement, i);
+            if (wasSelected)
+                treeElement.select(true);
+
+            var graphElement = treeElement._resourceGraph.graphElement;
+            this.resourcesGraphsElement.insertBefore(graphElement, this.resourcesGraphsElement.children[i]);
+        }
+    },
+
+    _updateGraphDividersIfNeeded: function(force)
+    {
+        if (!this.visible) {
+            this.needsRefresh = true;
+            return;
+        }
+
+        if (document.body.offsetWidth <= 0) {
+            // The stylesheet hasn't loaded yet or the window is closed,
+            // so we can't calculate what is need. Return early.
+            return;
+        }
+
+        var dividerCount = Math.round(this.dividersElement.offsetWidth / 64);
+        var slice = this.calculator.boundarySpan / dividerCount;
+        if (!force && this._currentDividerSlice === slice)
+            return;
+
+        this._currentDividerSlice = slice;
+
+        this.dividersElement.removeChildren();
+        this.dividersLabelBarElement.removeChildren();
+
+        for (var i = 1; i <= dividerCount; ++i) {
+            var divider = document.createElement("div");
+            divider.className = "resources-divider";
+            if (i === dividerCount)
+                divider.addStyleClass("last");
+            divider.style.left = ((i / dividerCount) * 100) + "%";
+
+            this.dividersElement.appendChild(divider.cloneNode());
+
+            var label = document.createElement("div");
+            label.className = "resources-divider-label";
+            if (!isNaN(slice))
+                label.textContent = this.calculator.formatValue(slice * i);
+            divider.appendChild(label);
+
+            this.dividersLabelBarElement.appendChild(divider);
+        }
+    },
+
+    _fadeOutRect: function(ctx, x, y, w, h, a1, a2)
+    {
+        ctx.save();
+
+        var gradient = ctx.createLinearGradient(x, y, x, y + h);
+        gradient.addColorStop(0.0, "rgba(0, 0, 0, " + (1.0 - a1) + ")");
+        gradient.addColorStop(0.8, "rgba(0, 0, 0, " + (1.0 - a2) + ")");
+        gradient.addColorStop(1.0, "rgba(0, 0, 0, 1.0)");
+
+        ctx.globalCompositeOperation = "destination-out";
+
+        ctx.fillStyle = gradient;
+        ctx.fillRect(x, y, w, h);
+
+        ctx.restore();
+    },
+
+    _drawSwatch: function(canvas, color)
+    {
+        var ctx = canvas.getContext("2d");
+
+        function drawSwatchSquare() {
+            ctx.fillStyle = color;
+            ctx.fillRect(0, 0, 13, 13);
+
+            var gradient = ctx.createLinearGradient(0, 0, 13, 13);
+            gradient.addColorStop(0.0, "rgba(255, 255, 255, 0.2)");
+            gradient.addColorStop(1.0, "rgba(255, 255, 255, 0.0)");
+
+            ctx.fillStyle = gradient;
+            ctx.fillRect(0, 0, 13, 13);
+
+            gradient = ctx.createLinearGradient(13, 13, 0, 0);
+            gradient.addColorStop(0.0, "rgba(0, 0, 0, 0.2)");
+            gradient.addColorStop(1.0, "rgba(0, 0, 0, 0.0)");
+
+            ctx.fillStyle = gradient;
+            ctx.fillRect(0, 0, 13, 13);
+
+            ctx.strokeStyle = "rgba(0, 0, 0, 0.6)";
+            ctx.strokeRect(0.5, 0.5, 12, 12);
+        }
+
+        ctx.clearRect(0, 0, 13, 24);
+
+        drawSwatchSquare();
+
+        ctx.save();
+
+        ctx.translate(0, 25);
+        ctx.scale(1, -1);
+
+        drawSwatchSquare();
+
+        ctx.restore();
+
+        this._fadeOutRect(ctx, 0, 13, 13, 13, 0.5, 0.0);
+    },
+
+    _drawSummaryGraph: function(segments)
+    {
+        if (!this.summaryGraphElement)
+            return;
+
+        if (!segments || !segments.length) {
+            segments = [{color: "white", value: 1}];
+            this._showingEmptySummaryGraph = true;
+        } else
+            delete this._showingEmptySummaryGraph;
+
+        // Calculate the total of all segments.
+        var total = 0;
+        for (var i = 0; i < segments.length; ++i)
+            total += segments[i].value;
+
+        // Calculate the percentage of each segment, rounded to the nearest percent.
+        var percents = segments.map(function(s) { return Math.max(Math.round(100 * s.value / total), 1) });
+
+        // Calculate the total percentage.
+        var percentTotal = 0;
+        for (var i = 0; i < percents.length; ++i)
+            percentTotal += percents[i];
+
+        // Make sure our percentage total is not greater-than 100, it can be greater
+        // if we rounded up for a few segments.
+        while (percentTotal > 100) {
+            for (var i = 0; i < percents.length && percentTotal > 100; ++i) {
+                if (percents[i] > 1) {
+                    --percents[i];
+                    --percentTotal;
+                }
+            }
+        }
+
+        // Make sure our percentage total is not less-than 100, it can be less
+        // if we rounded down for a few segments.
+        while (percentTotal < 100) {
+            for (var i = 0; i < percents.length && percentTotal < 100; ++i) {
+                ++percents[i];
+                ++percentTotal;
+            }
+        }
+
+        var ctx = this.summaryGraphElement.getContext("2d");
+
+        var x = 0;
+        var y = 0;
+        var w = 450;
+        var h = 19;
+        var r = (h / 2);
+
+        function drawPillShadow()
+        {
+            // This draws a line with a shadow that is offset away from the line. The line is stroked
+            // twice with different X shadow offsets to give more feathered edges. Later we erase the
+            // line with destination-out 100% transparent black, leaving only the shadow. This only
+            // works if nothing has been drawn into the canvas yet.
+
+            ctx.beginPath();
+            ctx.moveTo(x + 4, y + h - 3 - 0.5);
+            ctx.lineTo(x + w - 4, y + h - 3 - 0.5);
+            ctx.closePath();
+
+            ctx.save();
+
+            ctx.shadowBlur = 2;
+            ctx.shadowColor = "rgba(0, 0, 0, 0.5)";
+            ctx.shadowOffsetX = 3;
+            ctx.shadowOffsetY = 5;
+
+            ctx.strokeStyle = "white";
+            ctx.lineWidth = 1;
+
+            ctx.stroke();
+
+            ctx.shadowOffsetX = -3;
+
+            ctx.stroke();
+
+            ctx.restore();
+
+            ctx.save();
+
+            ctx.globalCompositeOperation = "destination-out";
+            ctx.strokeStyle = "rgba(0, 0, 0, 1)";
+            ctx.lineWidth = 1;
+
+            ctx.stroke();
+
+            ctx.restore();
+        }
+
+        function drawPill()
+        {
+            // Make a rounded rect path.
+            ctx.beginPath();
+            ctx.moveTo(x, y + r);
+            ctx.lineTo(x, y + h - r);
+            ctx.quadraticCurveTo(x, y + h, x + r, y + h);
+            ctx.lineTo(x + w - r, y + h);
+            ctx.quadraticCurveTo(x + w, y + h, x + w, y + h - r);
+            ctx.lineTo(x + w, y + r);
+            ctx.quadraticCurveTo(x + w, y, x + w - r, y);
+            ctx.lineTo(x + r, y);
+            ctx.quadraticCurveTo(x, y, x, y + r);
+            ctx.closePath();
+
+            // Clip to the rounded rect path.
+            ctx.save();
+            ctx.clip();
+
+            // Fill the segments with the associated color.
+            var previousSegmentsWidth = 0;
+            for (var i = 0; i < segments.length; ++i) {
+                var segmentWidth = Math.round(w * percents[i] / 100);
+                ctx.fillStyle = segments[i].color;
+                ctx.fillRect(x + previousSegmentsWidth, y, segmentWidth, h);
+                previousSegmentsWidth += segmentWidth;
+            }
+
+            // Draw the segment divider lines.
+            ctx.lineWidth = 1;
+            for (var i = 1; i < 20; ++i) {
+                ctx.beginPath();
+                ctx.moveTo(x + (i * Math.round(w / 20)) + 0.5, y);
+                ctx.lineTo(x + (i * Math.round(w / 20)) + 0.5, y + h);
+                ctx.closePath();
+
+                ctx.strokeStyle = "rgba(0, 0, 0, 0.2)";
+                ctx.stroke();
+
+                ctx.beginPath();
+                ctx.moveTo(x + (i * Math.round(w / 20)) + 1.5, y);
+                ctx.lineTo(x + (i * Math.round(w / 20)) + 1.5, y + h);
+                ctx.closePath();
+
+                ctx.strokeStyle = "rgba(255, 255, 255, 0.2)";
+                ctx.stroke();
+            }
+
+            // Draw the pill shading.
+            var lightGradient = ctx.createLinearGradient(x, y, x, y + (h / 1.5));
+            lightGradient.addColorStop(0.0, "rgba(220, 220, 220, 0.6)");
+            lightGradient.addColorStop(0.4, "rgba(220, 220, 220, 0.2)");
+            lightGradient.addColorStop(1.0, "rgba(255, 255, 255, 0.0)");
+
+            var darkGradient = ctx.createLinearGradient(x, y + (h / 3), x, y + h);
+            darkGradient.addColorStop(0.0, "rgba(0, 0, 0, 0.0)");
+            darkGradient.addColorStop(0.8, "rgba(0, 0, 0, 0.2)");
+            darkGradient.addColorStop(1.0, "rgba(0, 0, 0, 0.5)");
+
+            ctx.fillStyle = darkGradient;
+            ctx.fillRect(x, y, w, h);
+
+            ctx.fillStyle = lightGradient;
+            ctx.fillRect(x, y, w, h);
+
+            ctx.restore();
+        }
+
+        ctx.clearRect(x, y, w, (h * 2));
+
+        drawPillShadow();
+        drawPill();
+
+        ctx.save();
+
+        ctx.translate(0, (h * 2) + 1);
+        ctx.scale(1, -1);
+
+        drawPill();
+
+        ctx.restore();
+
+        this._fadeOutRect(ctx, x, y + h + 1, w, h, 0.5, 0.0);
+    },
+
+    _updateSummaryGraph: function()
+    {
+        var graphInfo = this.calculator.computeSummaryValues(this._resources);
+
+        var categoryOrder = ["documents", "stylesheets", "images", "scripts", "xhr", "fonts", "other"];
+        var categoryColors = {documents: {r: 47, g: 102, b: 236}, stylesheets: {r: 157, g: 231, b: 119}, images: {r: 164, g: 60, b: 255}, scripts: {r: 255, g: 121, b: 0}, xhr: {r: 231, g: 231, b: 10}, fonts: {r: 255, g: 82, b: 62}, other: {r: 186, g: 186, b: 186}};
+        var fillSegments = [];
+
+        this.legendElement.removeChildren();
+
+        for (var i = 0; i < categoryOrder.length; ++i) {
+            var category = categoryOrder[i];
+            var size = graphInfo.categoryValues[category];
+            if (!size)
+                continue;
+
+            var color = categoryColors[category];
+            var colorString = "rgb(" + color.r + ", " + color.g + ", " + color.b + ")";
+
+            var fillSegment = {color: colorString, value: size};
+            fillSegments.push(fillSegment);
+
+            var legendLabel = this._makeLegendElement(WebInspector.resourceCategories[category].title, this.calculator.formatValue(size), colorString);
+            this.legendElement.appendChild(legendLabel);
+        }
+
+        if (graphInfo.total) {
+            var totalLegendLabel = this._makeLegendElement(WebInspector.UIString("Total"), this.calculator.formatValue(graphInfo.total));
+            totalLegendLabel.addStyleClass("total");
+            this.legendElement.appendChild(totalLegendLabel);
+        }
+
+        this._drawSummaryGraph(fillSegments);
+    },
+
+    _updateDividersLabelBarPosition: function()
+    {
+        var scrollTop = this.containerElement.scrollTop;
+        var dividersTop = (scrollTop < this.summaryElement.offsetHeight ? this.summaryElement.offsetHeight : scrollTop);
+        this.dividersElement.style.top = scrollTop + "px";
+        this.dividersLabelBarElement.style.top = dividersTop + "px";
+    },
+
+    _graphSelected: function(treeElement)
+    {
+        if (this._lastSelectedGraphTreeElement)
+            this._lastSelectedGraphTreeElement.selectedSortingOptionIndex = this.sortingSelectElement.selectedIndex;
+
+        this._lastSelectedGraphTreeElement = treeElement;
+
+        this.sortingSelectElement.removeChildren();
+        for (var i = 0; i < treeElement.sortingOptions.length; ++i) {
+            var sortingOption = treeElement.sortingOptions[i];
+            var option = document.createElement("option");
+            option.label = sortingOption.name;
+            option.sortingFunction = sortingOption.sortingFunction;
+            option.calculator = sortingOption.calculator;
+            this.sortingSelectElement.appendChild(option);
+        }
+
+        this.sortingSelectElement.selectedIndex = treeElement.selectedSortingOptionIndex;
+        this._changeSortingFunction();
+
+        this.closeVisibleResource();
+        this.containerElement.scrollTop = 0;
+    },
+
+    _toggleLargerResources: function()
+    {
+        if (!this.resourcesTreeElement._childrenListNode)
+            return;
+
+        this.resourcesTreeElement.smallChildren = !this.resourcesTreeElement.smallChildren;
+
+        if (this.resourcesTreeElement.smallChildren) {
+            this.resourcesGraphsElement.addStyleClass("small");
+            this.largerResourcesButton.title = WebInspector.UIString("Use large resource rows.");
+            this.largerResourcesButton.removeStyleClass("toggled-on");
+            this._adjustScrollPosition();
+        } else {
+            this.resourcesGraphsElement.removeStyleClass("small");
+            this.largerResourcesButton.title = WebInspector.UIString("Use small resource rows.");
+            this.largerResourcesButton.addStyleClass("toggled-on");
+        }
+    },
+
+    _adjustScrollPosition: function()
+    {
+        // Prevent the container from being scrolled off the end.
+        if ((this.containerElement.scrollTop + this.containerElement.offsetHeight) > this.sidebarElement.offsetHeight)
+            this.containerElement.scrollTop = (this.sidebarElement.offsetHeight - this.containerElement.offsetHeight);
+    },
+
+    _changeSortingFunction: function()
+    {
+        var selectedOption = this.sortingSelectElement[this.sortingSelectElement.selectedIndex];
+        this.sortingFunction = selectedOption.sortingFunction;
+        this.calculator = selectedOption.calculator;
+    },
+
+    _createResourceView: function(resource)
+    {
+        switch (resource.category) {
+            case WebInspector.resourceCategories.documents:
+            case WebInspector.resourceCategories.stylesheets:
+            case WebInspector.resourceCategories.scripts:
+            case WebInspector.resourceCategories.xhr:
+                return new WebInspector.SourceView(resource);
+            case WebInspector.resourceCategories.images:
+                return new WebInspector.ImageView(resource);
+            case WebInspector.resourceCategories.fonts:
+                return new WebInspector.FontView(resource);
+            default:
+                return new WebInspector.ResourceView(resource);
+        }
+    },
+
+    _startSidebarDragging: function(event)
+    {
+        WebInspector.elementDragStart(this.sidebarResizeElement, this._sidebarDragging.bind(this), this._endSidebarDragging.bind(this), event, "col-resize");
+    },
+
+    _sidebarDragging: function(event)
+    {
+        this._updateSidebarWidth(event.pageX);
+
+        event.preventDefault();
+    },
+
+    _endSidebarDragging: function(event)
+    {
+        WebInspector.elementDragEnd(event);
+    },
+
+    _updateSidebarWidth: function(width)
+    {
+        if (this.sidebarElement.offsetWidth <= 0) {
+            // The stylesheet hasn't loaded yet or the window is closed,
+            // so we can't calculate what is need. Return early.
+            return;
+        }
+
+        if (!("_currentSidebarWidth" in this))
+            this._currentSidebarWidth = this.sidebarElement.offsetWidth;
+
+        if (typeof width === "undefined")
+            width = this._currentSidebarWidth;
+
+        width = Number.constrain(width, Preferences.minSidebarWidth, window.innerWidth / 2);
+
+        this._currentSidebarWidth = width;
+
+        if (this.visibleResource) {
+            this.containerElement.style.width = width + "px";
+            this.sidebarElement.style.removeProperty("width");
+        } else {
+            this.sidebarElement.style.width = width + "px";
+            this.containerElement.style.removeProperty("width");
+        }
+
+        this.containerContentElement.style.left = width + "px";
+        this.viewsContainerElement.style.left = width + "px";
+        this.sidebarResizeElement.style.left = (width - 3) + "px";
+
+        this._updateGraphDividersIfNeeded();
+
+        var visibleView = this.visibleView;
+        if (visibleView && "resize" in visibleView)
+            visibleView.resize();
+    }
+}
+
+WebInspector.ResourcesPanel.prototype.__proto__ = WebInspector.Panel.prototype;
+
+WebInspector.ResourceCalculator = function()
+{
+}
+
+WebInspector.ResourceCalculator.prototype = {
+    computeSummaryValues: function(resources)
+    {
+        var total = 0;
+        var categoryValues = {};
+
+        var resourcesLength = resources.length;
+        for (var i = 0; i < resourcesLength; ++i) {
+            var resource = resources[i];
+            var value = this._value(resource);
+            if (typeof value === "undefined")
+                continue;
+            if (!(resource.category.name in categoryValues))
+                categoryValues[resource.category.name] = 0;
+            categoryValues[resource.category.name] += value;
+            total += value;
+        }
+
+        return {categoryValues: categoryValues, total: total};
+    },
+
+    computeBarGraphPercentages: function(resource)
+    {
+        return {start: 0, middle: 0, end: (this._value(resource) / this.boundarySpan) * 100};
+    },
+
+    computeBarGraphLabels: function(resource)
+    {
+        const label = this.formatValue(this._value(resource));
+        var tooltip = label;
+        if (resource.cached)
+            tooltip = WebInspector.UIString("%s (from cache)", tooltip);
+        return {left: label, right: label, tooltip: tooltip};
+    },
+
+    get boundarySpan()
+    {
+        return this.maximumBoundary - this.minimumBoundary;
+    },
+
+    updateBoundaries: function(resource)
+    {
+        this.minimumBoundary = 0;
+
+        var value = this._value(resource);
+        if (typeof this.maximumBoundary === "undefined" || value > this.maximumBoundary) {
+            this.maximumBoundary = value;
+            return true;
+        }
+
+        return false;
+    },
+
+    reset: function()
+    {
+        delete this.minimumBoundary;
+        delete this.maximumBoundary;
+    },
+
+    _value: function(resource)
+    {
+        return 0;
+    },
+
+    formatValue: function(value)
+    {
+        return value.toString();
+    }
+}
+
+WebInspector.ResourceTimeCalculator = function(startAtZero)
+{
+    WebInspector.ResourceCalculator.call(this);
+    this.startAtZero = startAtZero;
+}
+
+WebInspector.ResourceTimeCalculator.prototype = {
+    computeSummaryValues: function(resources)
+    {
+        var resourcesByCategory = {};
+        var resourcesLength = resources.length;
+        for (var i = 0; i < resourcesLength; ++i) {
+            var resource = resources[i];
+            if (!(resource.category.name in resourcesByCategory))
+                resourcesByCategory[resource.category.name] = [];
+            resourcesByCategory[resource.category.name].push(resource);
+        }
+
+        var earliestStart;
+        var latestEnd;
+        var categoryValues = {};
+        for (var category in resourcesByCategory) {
+            resourcesByCategory[category].sort(WebInspector.Resource.CompareByTime);
+            categoryValues[category] = 0;
+
+            var segment = {start: -1, end: -1};
+
+            var categoryResources = resourcesByCategory[category];
+            var resourcesLength = categoryResources.length;
+            for (var i = 0; i < resourcesLength; ++i) {
+                var resource = categoryResources[i];
+                if (resource.startTime === -1 || resource.endTime === -1)
+                    continue;
+
+                if (typeof earliestStart === "undefined")
+                    earliestStart = resource.startTime;
+                else
+                    earliestStart = Math.min(earliestStart, resource.startTime);
+
+                if (typeof latestEnd === "undefined")
+                    latestEnd = resource.endTime;
+                else
+                    latestEnd = Math.max(latestEnd, resource.endTime);
+
+                if (resource.startTime <= segment.end) {
+                    segment.end = Math.max(segment.end, resource.endTime);
+                    continue;
+                }
+
+                categoryValues[category] += segment.end - segment.start;
+
+                segment.start = resource.startTime;
+                segment.end = resource.endTime;
+            }
+
+            // Add the last segment
+            categoryValues[category] += segment.end - segment.start;
+        }
+
+        return {categoryValues: categoryValues, total: latestEnd - earliestStart};
+    },
+
+    computeBarGraphPercentages: function(resource)
+    {
+        if (resource.startTime !== -1)
+            var start = ((resource.startTime - this.minimumBoundary) / this.boundarySpan) * 100;
+        else
+            var start = 0;
+
+        if (resource.responseReceivedTime !== -1)
+            var middle = ((resource.responseReceivedTime - this.minimumBoundary) / this.boundarySpan) * 100;
+        else
+            var middle = (this.startAtZero ? start : 100);
+
+        if (resource.endTime !== -1)
+            var end = ((resource.endTime - this.minimumBoundary) / this.boundarySpan) * 100;
+        else
+            var end = (this.startAtZero ? middle : 100);
+
+        if (this.startAtZero) {
+            end -= start;
+            middle -= start;
+            start = 0;
+        }
+
+        return {start: start, middle: middle, end: end};
+    },
+
+    computeBarGraphLabels: function(resource)
+    {
+        var leftLabel = "";
+        if (resource.latency > 0)
+            leftLabel = this.formatValue(resource.latency);
+
+        var rightLabel = "";
+        if (resource.responseReceivedTime !== -1 && resource.endTime !== -1)
+            rightLabel = this.formatValue(resource.endTime - resource.responseReceivedTime);
+
+        if (leftLabel && rightLabel) {
+            var total = this.formatValue(resource.duration);
+            var tooltip = WebInspector.UIString("%s latency, %s download (%s total)", leftLabel, rightLabel, total);
+        } else if (leftLabel)
+            var tooltip = WebInspector.UIString("%s latency", leftLabel);
+        else if (rightLabel)
+            var tooltip = WebInspector.UIString("%s download", rightLabel);
+
+        if (resource.cached)
+            tooltip = WebInspector.UIString("%s (from cache)", tooltip);
+
+        return {left: leftLabel, right: rightLabel, tooltip: tooltip};
+    },
+
+    updateBoundaries: function(resource)
+    {
+        var didChange = false;
+
+        var lowerBound;
+        if (this.startAtZero)
+            lowerBound = 0;
+        else
+            lowerBound = this._lowerBound(resource);
+
+        if (lowerBound !== -1 && (typeof this.minimumBoundary === "undefined" || lowerBound < this.minimumBoundary)) {
+            this.minimumBoundary = lowerBound;
+            didChange = true;
+        }
+
+        var upperBound = this._upperBound(resource);
+        if (upperBound !== -1 && (typeof this.maximumBoundary === "undefined" || upperBound > this.maximumBoundary)) {
+            this.maximumBoundary = upperBound;
+            didChange = true;
+        }
+
+        return didChange;
+    },
+
+    formatValue: function(value)
+    {
+        return Number.secondsToString(value, WebInspector.UIString.bind(WebInspector));
+    },
+
+    _lowerBound: function(resource)
+    {
+        return 0;
+    },
+
+    _upperBound: function(resource)
+    {
+        return 0;
+    },
+}
+
+WebInspector.ResourceTimeCalculator.prototype.__proto__ = WebInspector.ResourceCalculator.prototype;
+
+WebInspector.ResourceTransferTimeCalculator = function()
+{
+    WebInspector.ResourceTimeCalculator.call(this, false);
+}
+
+WebInspector.ResourceTransferTimeCalculator.prototype = {
+    formatValue: function(value)
+    {
+        return Number.secondsToString(value, WebInspector.UIString.bind(WebInspector));
+    },
+
+    _lowerBound: function(resource)
+    {
+        return resource.startTime;
+    },
+
+    _upperBound: function(resource)
+    {
+        return resource.endTime;
+    }
+}
+
+WebInspector.ResourceTransferTimeCalculator.prototype.__proto__ = WebInspector.ResourceTimeCalculator.prototype;
+
+WebInspector.ResourceTransferDurationCalculator = function()
+{
+    WebInspector.ResourceTimeCalculator.call(this, true);
+}
+
+WebInspector.ResourceTransferDurationCalculator.prototype = {
+    formatValue: function(value)
+    {
+        return Number.secondsToString(value, WebInspector.UIString.bind(WebInspector));
+    },
+
+    _upperBound: function(resource)
+    {
+        return resource.duration;
+    }
+}
+
+WebInspector.ResourceTransferDurationCalculator.prototype.__proto__ = WebInspector.ResourceTimeCalculator.prototype;
+
+WebInspector.ResourceTransferSizeCalculator = function()
+{
+    WebInspector.ResourceCalculator.call(this);
+}
+
+WebInspector.ResourceTransferSizeCalculator.prototype = {
+    _value: function(resource)
+    {
+        return resource.contentLength;
+    },
+
+    formatValue: function(value)
+    {
+        return Number.bytesToString(value, WebInspector.UIString.bind(WebInspector));
+    }
+}
+
+WebInspector.ResourceTransferSizeCalculator.prototype.__proto__ = WebInspector.ResourceCalculator.prototype;
+
+WebInspector.ResourceSidebarTreeElement = function(resource)
+{
+    this.resource = resource;
+
+    this.createIconElement();
+
+    WebInspector.SidebarTreeElement.call(this, "resource-sidebar-tree-item", "", "", resource);
+
+    this.refreshTitles();
+}
+
+WebInspector.ResourceSidebarTreeElement.prototype = {
+    onattach: function()
+    {
+        WebInspector.SidebarTreeElement.prototype.onattach.call(this);
+
+        this._listItemNode.addStyleClass("resources-category-" + this.resource.category.name);
+    },
+
+    onselect: function()
+    {
+        WebInspector.panels.resources.showResource(this.resource);
+    },
+
+    get mainTitle()
+    {
+        return this.resource.displayName;
+    },
+
+    set mainTitle(x)
+    {
+        // Do nothing.
+    },
+
+    get subtitle()
+    {
+        var subtitle = this.resource.displayDomain;
+
+        if (this.resource.path && this.resource.lastPathComponent) {
+            var lastPathComponentIndex = this.resource.path.lastIndexOf("/" + this.resource.lastPathComponent);
+            if (lastPathComponentIndex != -1)
+                subtitle += this.resource.path.substring(0, lastPathComponentIndex);
+        }
+
+        return subtitle;
+    },
+
+    set subtitle(x)
+    {
+        // Do nothing.
+    },
+
+    createIconElement: function()
+    {
+        var previousIconElement = this.iconElement;
+
+        if (this.resource.category === WebInspector.resourceCategories.images) {
+            var previewImage = document.createElement("img");
+            previewImage.className = "image-resource-icon-preview";
+            previewImage.src = this.resource.url;
+
+            this.iconElement = document.createElement("div");
+            this.iconElement.className = "icon";
+            this.iconElement.appendChild(previewImage);
+        } else {
+            this.iconElement = document.createElement("img");
+            this.iconElement.className = "icon";
+        }
+
+        if (previousIconElement)
+            previousIconElement.parentNode.replaceChild(this.iconElement, previousIconElement);
+    },
+
+    refresh: function()
+    {
+        this.refreshTitles();
+
+        if (!this._listItemNode.hasStyleClass("resources-category-" + this.resource.category.name)) {
+            this._listItemNode.removeMatchingStyleClasses("resources-category-\\w+");
+            this._listItemNode.addStyleClass("resources-category-" + this.resource.category.name);
+
+            this.createIconElement();
+        }
+    },
+
+    resetBubble: function()
+    {
+        this.bubbleText = "";
+        this.bubbleElement.removeStyleClass("search-matches");
+        this.bubbleElement.removeStyleClass("warning");
+        this.bubbleElement.removeStyleClass("error");
+    },
+
+    set searchMatches(matches)
+    {
+        this.resetBubble();
+
+        if (!matches)
+            return;
+
+        this.bubbleText = matches;
+        this.bubbleElement.addStyleClass("search-matches");
+    },
+
+    updateErrorsAndWarnings: function()
+    {
+        this.resetBubble();
+
+        if (this.resource.warnings || this.resource.errors)
+            this.bubbleText = (this.resource.warnings + this.resource.errors);
+
+        if (this.resource.warnings)
+            this.bubbleElement.addStyleClass("warning");
+
+        if (this.resource.errors)
+            this.bubbleElement.addStyleClass("error");
+    }
+}
+
+WebInspector.ResourceSidebarTreeElement.CompareByAscendingStartTime = function(a, b)
+{
+    return WebInspector.Resource.CompareByStartTime(a.resource, b.resource)
+        || WebInspector.Resource.CompareByEndTime(a.resource, b.resource)
+        || WebInspector.Resource.CompareByResponseReceivedTime(a.resource, b.resource);
+}
+
+WebInspector.ResourceSidebarTreeElement.CompareByAscendingResponseReceivedTime = function(a, b)
+{
+    return WebInspector.Resource.CompareByResponseReceivedTime(a.resource, b.resource)
+        || WebInspector.Resource.CompareByStartTime(a.resource, b.resource)
+        || WebInspector.Resource.CompareByEndTime(a.resource, b.resource);
+}
+
+WebInspector.ResourceSidebarTreeElement.CompareByAscendingEndTime = function(a, b)
+{
+    return WebInspector.Resource.CompareByEndTime(a.resource, b.resource)
+        || WebInspector.Resource.CompareByStartTime(a.resource, b.resource)
+        || WebInspector.Resource.CompareByResponseReceivedTime(a.resource, b.resource);
+}
+
+WebInspector.ResourceSidebarTreeElement.CompareByDescendingDuration = function(a, b)
+{
+    return -1 * WebInspector.Resource.CompareByDuration(a.resource, b.resource);
+}
+
+WebInspector.ResourceSidebarTreeElement.CompareByDescendingLatency = function(a, b)
+{
+    return -1 * WebInspector.Resource.CompareByLatency(a.resource, b.resource);
+}
+
+WebInspector.ResourceSidebarTreeElement.CompareByDescendingSize = function(a, b)
+{
+    return -1 * WebInspector.Resource.CompareBySize(a.resource, b.resource);
+}
+
+WebInspector.ResourceSidebarTreeElement.prototype.__proto__ = WebInspector.SidebarTreeElement.prototype;
+
+WebInspector.ResourceGraph = function(resource)
+{
+    this.resource = resource;
+
+    this._graphElement = document.createElement("div");
+    this._graphElement.className = "resources-graph-side";
+    this._graphElement.addEventListener("mouseover", this.refreshLabelPositions.bind(this), false);
+
+    if (resource.cached)
+        this._graphElement.addStyleClass("resource-cached");
+
+    this._barAreaElement = document.createElement("div");
+    this._barAreaElement.className = "resources-graph-bar-area hidden";
+    this._graphElement.appendChild(this._barAreaElement);
+
+    this._barLeftElement = document.createElement("div");
+    this._barLeftElement.className = "resources-graph-bar waiting";
+    this._barAreaElement.appendChild(this._barLeftElement);
+
+    this._barRightElement = document.createElement("div");
+    this._barRightElement.className = "resources-graph-bar";
+    this._barAreaElement.appendChild(this._barRightElement);
+
+    this._labelLeftElement = document.createElement("div");
+    this._labelLeftElement.className = "resources-graph-label waiting";
+    this._barAreaElement.appendChild(this._labelLeftElement);
+
+    this._labelRightElement = document.createElement("div");
+    this._labelRightElement.className = "resources-graph-label";
+    this._barAreaElement.appendChild(this._labelRightElement);
+
+    this._graphElement.addStyleClass("resources-category-" + resource.category.name);
+}
+
+WebInspector.ResourceGraph.prototype = {
+    get graphElement()
+    {
+        return this._graphElement;
+    },
+
+    refreshLabelPositions: function()
+    {
+        this._labelLeftElement.style.removeProperty("left");
+        this._labelLeftElement.style.removeProperty("right");
+        this._labelLeftElement.removeStyleClass("before");
+        this._labelLeftElement.removeStyleClass("hidden");
+
+        this._labelRightElement.style.removeProperty("left");
+        this._labelRightElement.style.removeProperty("right");
+        this._labelRightElement.removeStyleClass("after");
+        this._labelRightElement.removeStyleClass("hidden");
+
+        const labelPadding = 10;
+        const rightBarWidth = (this._barRightElement.offsetWidth - labelPadding);
+        const leftBarWidth = ((this._barLeftElement.offsetWidth - this._barRightElement.offsetWidth) - labelPadding);
+
+        var labelBefore = (this._labelLeftElement.offsetWidth > leftBarWidth);
+        var labelAfter = (this._labelRightElement.offsetWidth > rightBarWidth);
+
+        if (labelBefore) {
+            if ((this._graphElement.offsetWidth * (this._percentages.start / 100)) < (this._labelLeftElement.offsetWidth + 10))
+                this._labelLeftElement.addStyleClass("hidden");
+            this._labelLeftElement.style.setProperty("right", (100 - this._percentages.start) + "%");
+            this._labelLeftElement.addStyleClass("before");
+        } else {
+            this._labelLeftElement.style.setProperty("left", this._percentages.start + "%");
+            this._labelLeftElement.style.setProperty("right", (100 - this._percentages.middle) + "%");
+        }
+
+        if (labelAfter) {
+            if ((this._graphElement.offsetWidth * ((100 - this._percentages.end) / 100)) < (this._labelRightElement.offsetWidth + 10))
+                this._labelRightElement.addStyleClass("hidden");
+            this._labelRightElement.style.setProperty("left", this._percentages.end + "%");
+            this._labelRightElement.addStyleClass("after");
+        } else {
+            this._labelRightElement.style.setProperty("left", this._percentages.middle + "%");
+            this._labelRightElement.style.setProperty("right", (100 - this._percentages.end) + "%");
+        }
+    },
+
+    refresh: function(calculator)
+    {
+        var percentages = calculator.computeBarGraphPercentages(this.resource);
+        var labels = calculator.computeBarGraphLabels(this.resource);
+
+        this._percentages = percentages;
+
+        this._barAreaElement.removeStyleClass("hidden");
+
+        if (!this._graphElement.hasStyleClass("resources-category-" + this.resource.category.name)) {
+            this._graphElement.removeMatchingStyleClasses("resources-category-\\w+");
+            this._graphElement.addStyleClass("resources-category-" + this.resource.category.name);
+        }
+
+        this._barLeftElement.style.setProperty("left", percentages.start + "%");
+        this._barLeftElement.style.setProperty("right", (100 - percentages.end) + "%");
+
+        this._barRightElement.style.setProperty("left", percentages.middle + "%");
+        this._barRightElement.style.setProperty("right", (100 - percentages.end) + "%");
+
+        this._labelLeftElement.textContent = labels.left;
+        this._labelRightElement.textContent = labels.right;
+
+        var tooltip = (labels.tooltip || "");
+        this._barLeftElement.title = tooltip;
+        this._labelLeftElement.title = tooltip;
+        this._labelRightElement.title = tooltip;
+        this._barRightElement.title = tooltip;
+    }
+}
diff --git a/resources/Inspector/ScriptsPanel.js b/resources/Inspector/ScriptsPanel.js
new file mode 100644
index 0000000..38a6a96
--- /dev/null
+++ b/resources/Inspector/ScriptsPanel.js
@@ -0,0 +1,810 @@
+/*
+ * 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.ScriptsPanel = function()
+{
+    WebInspector.Panel.call(this);
+
+    this.element.addStyleClass("scripts");
+
+    this.topStatusBar = document.createElement("div");
+    this.topStatusBar.className = "status-bar";
+    this.topStatusBar.id = "scripts-status-bar";
+    this.element.appendChild(this.topStatusBar);
+
+    this.backButton = document.createElement("button");
+    this.backButton.className = "status-bar-item";
+    this.backButton.id = "scripts-back";
+    this.backButton.title = WebInspector.UIString("Show the previous script resource.");
+    this.backButton.disabled = true;
+    this.backButton.appendChild(document.createElement("img"));
+    this.backButton.addEventListener("click", this._goBack.bind(this), false);
+    this.topStatusBar.appendChild(this.backButton);
+
+    this.forwardButton = document.createElement("button");
+    this.forwardButton.className = "status-bar-item";
+    this.forwardButton.id = "scripts-forward";
+    this.forwardButton.title = WebInspector.UIString("Show the next script resource.");
+    this.forwardButton.disabled = true;
+    this.forwardButton.appendChild(document.createElement("img"));
+    this.forwardButton.addEventListener("click", this._goForward.bind(this), false);
+    this.topStatusBar.appendChild(this.forwardButton);
+
+    this.filesSelectElement = document.createElement("select");
+    this.filesSelectElement.className = "status-bar-item";
+    this.filesSelectElement.id = "scripts-files";
+    this.filesSelectElement.addEventListener("change", this._changeVisibleFile.bind(this), false);
+    this.topStatusBar.appendChild(this.filesSelectElement);
+
+    this.functionsSelectElement = document.createElement("select");
+    this.functionsSelectElement.className = "status-bar-item";
+    this.functionsSelectElement.id = "scripts-functions";
+
+    // FIXME: append the functions select element to the top status bar when it is implemented.
+    // this.topStatusBar.appendChild(this.functionsSelectElement);
+
+    this.sidebarButtonsElement = document.createElement("div");
+    this.sidebarButtonsElement.id = "scripts-sidebar-buttons";
+    this.topStatusBar.appendChild(this.sidebarButtonsElement);
+
+    this.pauseButton = document.createElement("button");
+    this.pauseButton.className = "status-bar-item";
+    this.pauseButton.id = "scripts-pause";
+    this.pauseButton.title = WebInspector.UIString("Pause script execution.");
+    this.pauseButton.disabled = true;
+    this.pauseButton.appendChild(document.createElement("img"));
+    this.pauseButton.addEventListener("click", this._togglePause.bind(this), false);
+    this.sidebarButtonsElement.appendChild(this.pauseButton);
+
+    this.stepOverButton = document.createElement("button");
+    this.stepOverButton.className = "status-bar-item";
+    this.stepOverButton.id = "scripts-step-over";
+    this.stepOverButton.title = WebInspector.UIString("Step over next function call.");
+    this.stepOverButton.disabled = true;
+    this.stepOverButton.addEventListener("click", this._stepOverClicked.bind(this), false);
+    this.stepOverButton.appendChild(document.createElement("img"));
+    this.sidebarButtonsElement.appendChild(this.stepOverButton);
+
+    this.stepIntoButton = document.createElement("button");
+    this.stepIntoButton.className = "status-bar-item";
+    this.stepIntoButton.id = "scripts-step-into";
+    this.stepIntoButton.title = WebInspector.UIString("Step into next function call.");
+    this.stepIntoButton.disabled = true;
+    this.stepIntoButton.addEventListener("click", this._stepIntoClicked.bind(this), false);
+    this.stepIntoButton.appendChild(document.createElement("img"));
+    this.sidebarButtonsElement.appendChild(this.stepIntoButton);
+
+    this.stepOutButton = document.createElement("button");
+    this.stepOutButton.className = "status-bar-item";
+    this.stepOutButton.id = "scripts-step-out";
+    this.stepOutButton.title = WebInspector.UIString("Step out of current function.");
+    this.stepOutButton.disabled = true;
+    this.stepOutButton.addEventListener("click", this._stepOutClicked.bind(this), false);
+    this.stepOutButton.appendChild(document.createElement("img"));
+    this.sidebarButtonsElement.appendChild(this.stepOutButton);
+
+    this.debuggerStatusElement = document.createElement("div");
+    this.debuggerStatusElement.id = "scripts-debugger-status";
+    this.sidebarButtonsElement.appendChild(this.debuggerStatusElement);
+
+    this.viewsContainerElement = document.createElement("div");
+    this.viewsContainerElement.id = "script-resource-views";
+
+    this.sidebarElement = document.createElement("div");
+    this.sidebarElement.id = "scripts-sidebar";
+
+    this.sidebarResizeElement = document.createElement("div");
+    this.sidebarResizeElement.className = "sidebar-resizer-vertical";
+    this.sidebarResizeElement.addEventListener("mousedown", this._startSidebarResizeDrag.bind(this), false);
+
+    this.sidebarResizeWidgetElement = document.createElement("div");
+    this.sidebarResizeWidgetElement.id = "scripts-sidebar-resizer-widget";
+    this.sidebarResizeWidgetElement.addEventListener("mousedown", this._startSidebarResizeDrag.bind(this), false);
+    this.topStatusBar.appendChild(this.sidebarResizeWidgetElement);
+
+    this.sidebarPanes = {};
+    this.sidebarPanes.callstack = new WebInspector.CallStackSidebarPane();
+    this.sidebarPanes.scopechain = new WebInspector.ScopeChainSidebarPane();
+    this.sidebarPanes.breakpoints = new WebInspector.BreakpointsSidebarPane();
+
+    for (var pane in this.sidebarPanes)
+        this.sidebarElement.appendChild(this.sidebarPanes[pane].element);
+
+    // FIXME: remove the following line of code when the Breakpoints pane has content.
+    this.sidebarElement.removeChild(this.sidebarPanes.breakpoints.element);
+
+    this.sidebarPanes.callstack.expanded = true;
+    this.sidebarPanes.callstack.addEventListener("call frame selected", this._callFrameSelected, this);
+
+    this.sidebarPanes.scopechain.expanded = true;
+
+    var panelEnablerHeading = WebInspector.UIString("You need to enable debugging before you can use the Scripts panel.");
+    var panelEnablerDisclaimer = WebInspector.UIString("Enabling debugging will make scripts run slower.");
+    var panelEnablerButton = WebInspector.UIString("Enable Debugging");
+
+    this.panelEnablerView = new WebInspector.PanelEnablerView("scripts", panelEnablerHeading, panelEnablerDisclaimer, panelEnablerButton);
+    this.panelEnablerView.addEventListener("enable clicked", this._enableDebugging, this);
+
+    this.element.appendChild(this.panelEnablerView.element);
+    this.element.appendChild(this.viewsContainerElement);
+    this.element.appendChild(this.sidebarElement);
+    this.element.appendChild(this.sidebarResizeElement);
+
+    this.enableToggleButton = document.createElement("button");
+    this.enableToggleButton.className = "enable-toggle-status-bar-item status-bar-item";
+    this.enableToggleButton.addEventListener("click", this._toggleDebugging.bind(this), false);
+
+    this.pauseOnExceptionButton = document.createElement("button");
+    this.pauseOnExceptionButton.id = "scripts-pause-on-exceptions-status-bar-item";
+    this.pauseOnExceptionButton.className = "status-bar-item";
+    this.pauseOnExceptionButton.addEventListener("click", this._togglePauseOnExceptions.bind(this), false);
+
+    this._breakpointsURLMap = {};
+
+    this.reset();
+}
+
+WebInspector.ScriptsPanel.prototype = {
+    toolbarItemClass: "scripts",
+
+    get toolbarItemLabel()
+    {
+        return WebInspector.UIString("Scripts");
+    },
+
+    get statusBarItems()
+    {
+        return [this.enableToggleButton, this.pauseOnExceptionButton];
+    },
+
+    get paused()
+    {
+        return this._paused;
+    },
+
+    show: function()
+    {
+        WebInspector.Panel.prototype.show.call(this);
+        this.sidebarResizeElement.style.right = (this.sidebarElement.offsetWidth - 3) + "px";
+
+        if (this.visibleView) {
+            if (this.visibleView instanceof WebInspector.ResourceView)
+                this.visibleView.headersVisible = false;
+            this.visibleView.show(this.viewsContainerElement);
+        }
+
+        // Hide any views that are visible that are not this panel's current visible view.
+        // This can happen when a ResourceView is visible in the Resources panel then switched
+        // to the this panel.
+        for (var sourceID in this._sourceIDMap) {
+            var scriptOrResource = this._sourceIDMap[sourceID];
+            var view = this._sourceViewForScriptOrResource(scriptOrResource);
+            if (!view || view === this.visibleView)
+                continue;
+            view.visible = false;
+        }
+    },
+
+    get searchableViews()
+    {
+        var views = [];
+
+        const visibleView = this.visibleView;
+        if (visibleView && visibleView.performSearch) {
+            visibleView.alreadySearching = true;
+            views.push(visibleView);
+        }
+
+        for (var sourceID in this._sourceIDMap) {
+            var scriptOrResource = this._sourceIDMap[sourceID];
+            var view = this._sourceViewForScriptOrResource(scriptOrResource);
+            if (!view || !view.performSearch || view.alreadySearching)
+                continue;
+
+            view.alreadySearching = true;
+            views.push(view);
+        }
+
+        for (var i = 0; i < views.length; ++i)
+            delete views[i].alreadySearching;
+
+        return views;
+    },
+
+    addScript: function(sourceID, sourceURL, source, startingLine, errorLine, errorMessage)
+    {
+        var script = new WebInspector.Script(sourceID, sourceURL, source, startingLine, errorLine, errorMessage);
+
+        if (sourceURL in WebInspector.resourceURLMap) {
+            var resource = WebInspector.resourceURLMap[sourceURL];
+            resource.addScript(script);
+        }
+
+        if (sourceURL in this._breakpointsURLMap && sourceID) {
+            var breakpoints = this._breakpointsURLMap[sourceURL];
+            var breakpointsLength = breakpoints.length;
+            for (var i = 0; i < breakpointsLength; ++i) {
+                var breakpoint = breakpoints[i];
+                if (startingLine <= breakpoint.line) {
+                    breakpoint.sourceID = sourceID;
+                    if (breakpoint.enabled)
+                        InspectorController.addBreakpoint(breakpoint.sourceID, breakpoint.line);
+                }
+            }
+        }
+
+        if (sourceID)
+            this._sourceIDMap[sourceID] = (resource || script);
+
+        this._addScriptToFilesMenu(script);
+    },
+
+    addBreakpoint: function(breakpoint)
+    {
+        this.sidebarPanes.breakpoints.addBreakpoint(breakpoint);
+
+        var sourceFrame;
+        if (breakpoint.url) {
+            if (!(breakpoint.url in this._breakpointsURLMap))
+                this._breakpointsURLMap[breakpoint.url] = [];
+            this._breakpointsURLMap[breakpoint.url].unshift(breakpoint);
+
+            if (breakpoint.url in WebInspector.resourceURLMap) {
+                var resource = WebInspector.resourceURLMap[breakpoint.url];
+                sourceFrame = this._sourceFrameForScriptOrResource(resource);
+            }
+        }
+
+        if (breakpoint.sourceID && !sourceFrame) {
+            var object = this._sourceIDMap[breakpoint.sourceID]
+            sourceFrame = this._sourceFrameForScriptOrResource(object);
+        }
+
+        if (sourceFrame)
+            sourceFrame.addBreakpoint(breakpoint);
+    },
+
+    removeBreakpoint: function(breakpoint)
+    {
+        this.sidebarPanes.breakpoints.removeBreakpoint(breakpoint);
+
+        var sourceFrame;
+        if (breakpoint.url && breakpoint.url in this._breakpointsURLMap) {
+            var breakpoints = this._breakpointsURLMap[breakpoint.url];
+            breakpoints.remove(breakpoint);
+            if (!breakpoints.length)
+                delete this._breakpointsURLMap[breakpoint.url];
+
+            if (breakpoint.url in WebInspector.resourceURLMap) {
+                var resource = WebInspector.resourceURLMap[breakpoint.url];
+                sourceFrame = this._sourceFrameForScriptOrResource(resource);
+            }
+        }
+
+        if (breakpoint.sourceID && !sourceFrame) {
+            var object = this._sourceIDMap[breakpoint.sourceID]
+            sourceFrame = this._sourceFrameForScriptOrResource(object);
+        }
+
+        if (sourceFrame)
+            sourceFrame.removeBreakpoint(breakpoint);
+    },
+
+    evaluateInSelectedCallFrame: function(code, updateInterface)
+    {
+        var selectedCallFrame = this.sidebarPanes.callstack.selectedCallFrame;
+        if (!this._paused || !selectedCallFrame)
+            return;
+        if (typeof updateInterface === "undefined")
+            updateInterface = true;
+        var result = selectedCallFrame.evaluate(code);
+        if (updateInterface)
+            this.sidebarPanes.scopechain.update(selectedCallFrame);
+        return result;
+    },
+
+    variablesInScopeForSelectedCallFrame: function()
+    {
+        var selectedCallFrame = this.sidebarPanes.callstack.selectedCallFrame;
+        if (!this._paused || !selectedCallFrame)
+            return {};
+
+        var result = {};
+        var scopeChain = selectedCallFrame.scopeChain;
+        for (var i = 0; i < scopeChain.length; ++i) {
+            var scopeObject = scopeChain[i];
+            for (var property in scopeObject)
+                result[property] = true;
+        }
+
+        return result;
+    },
+
+    debuggerPaused: function()
+    {
+        this._paused = true;
+        this._waitingToPause = false;
+        this._stepping = false;
+
+        this._updateDebuggerButtons();
+
+        var callStackPane = this.sidebarPanes.callstack;
+        var currentFrame = InspectorController.currentCallFrame();
+        callStackPane.update(currentFrame, this._sourceIDMap);
+        callStackPane.selectedCallFrame = currentFrame;
+
+        WebInspector.currentPanel = this;
+        window.focus();
+    },
+
+    debuggerWasEnabled: function()
+    {
+        this.reset();
+    },
+
+    debuggerWasDisabled: function()
+    {
+        this.reset();
+    },
+
+    reset: function()
+    {
+        this.visibleView = null;
+
+        delete this.currentQuery;
+        this.searchCanceled();
+
+        if (!InspectorController.debuggerEnabled()) {
+            this._paused = false;
+            this._waitingToPause = false;
+            this._stepping = false;
+        }
+
+        this._clearInterface();
+
+        this._backForwardList = [];
+        this._currentBackForwardIndex = -1;
+        this._updateBackAndForwardButtons();
+
+        this._scriptsForURLsInFilesSelect = {};
+        this.filesSelectElement.removeChildren();
+        this.functionsSelectElement.removeChildren();
+        this.viewsContainerElement.removeChildren();
+
+        if (this._sourceIDMap) {
+            for (var sourceID in this._sourceIDMap) {
+                var object = this._sourceIDMap[sourceID];
+                if (object instanceof WebInspector.Resource)
+                    object.removeAllScripts();
+            }
+        }
+
+        this._sourceIDMap = {};
+    },
+
+    get visibleView()
+    {
+        return this._visibleView;
+    },
+
+    set visibleView(x)
+    {
+        if (this._visibleView === x)
+            return;
+
+        if (this._visibleView)
+            this._visibleView.hide();
+
+        this._visibleView = x;
+
+        if (x)
+            x.show(this.viewsContainerElement);
+    },
+
+    canShowResource: function(resource)
+    {
+        return resource && resource.scripts.length && InspectorController.debuggerEnabled();
+    },
+
+    showScript: function(script, line)
+    {
+        this._showScriptOrResource(script, line, true);
+    },
+
+    showResource: function(resource, line)
+    {
+        this._showScriptOrResource(resource, line, true);
+    },
+
+    showView: function(view)
+    {
+        if (!view)
+            return;
+        this._showScriptOrResource((view.resource || view.script));
+    },
+
+    scriptViewForScript: function(script)
+    {
+        if (!script)
+            return null;
+        if (!script._scriptView)
+            script._scriptView = new WebInspector.ScriptView(script);
+        return script._scriptView;
+    },
+
+    sourceFrameForScript: function(script)
+    {
+        var view = this.scriptViewForScript(script);
+        if (!view)
+            return null;
+
+        // Setting up the source frame requires that we be attached.
+        if (!this.element.parentNode)
+            this.attach();
+
+        view.setupSourceFrameIfNeeded();
+        return view.sourceFrame;
+    },
+
+    _sourceViewForScriptOrResource: function(scriptOrResource)
+    {
+        if (scriptOrResource instanceof WebInspector.Resource) {
+            if (!WebInspector.panels.resources)
+                return null;
+            return WebInspector.panels.resources.resourceViewForResource(scriptOrResource);
+        }
+        if (scriptOrResource instanceof WebInspector.Script)
+            return this.scriptViewForScript(scriptOrResource);
+    },
+
+    _sourceFrameForScriptOrResource: function(scriptOrResource)
+    {
+        if (scriptOrResource instanceof WebInspector.Resource) {
+            if (!WebInspector.panels.resources)
+                return null;
+            return WebInspector.panels.resources.sourceFrameForResource(scriptOrResource);
+        }
+        if (scriptOrResource instanceof WebInspector.Script)
+            return this.sourceFrameForScript(scriptOrResource);
+    },
+
+    _showScriptOrResource: function(scriptOrResource, line, shouldHighlightLine, fromBackForwardAction)
+    {
+        if (!scriptOrResource)
+            return;
+
+        var view;
+        if (scriptOrResource instanceof WebInspector.Resource) {
+            if (!WebInspector.panels.resources)
+                return null;
+            view = WebInspector.panels.resources.resourceViewForResource(scriptOrResource);
+            view.headersVisible = false;
+
+            if (scriptOrResource.url in this._breakpointsURLMap) {
+                var sourceFrame = this._sourceFrameForScriptOrResource(scriptOrResource);
+                if (sourceFrame && !sourceFrame.breakpoints.length) {
+                    var breakpoints = this._breakpointsURLMap[scriptOrResource.url];
+                    var breakpointsLength = breakpoints.length;
+                    for (var i = 0; i < breakpointsLength; ++i)
+                        sourceFrame.addBreakpoint(breakpoints[i]);
+                }
+            }
+        } else if (scriptOrResource instanceof WebInspector.Script)
+            view = this.scriptViewForScript(scriptOrResource);
+
+        if (!view)
+            return;
+
+        if (!fromBackForwardAction) {
+            var oldIndex = this._currentBackForwardIndex;
+            if (oldIndex >= 0)
+                this._backForwardList.splice(oldIndex + 1, this._backForwardList.length - oldIndex);
+
+            // Check for a previous entry of the same object in _backForwardList.
+            // If one is found, remove it and update _currentBackForwardIndex to match.
+            var previousEntryIndex = this._backForwardList.indexOf(scriptOrResource);
+            if (previousEntryIndex !== -1) {
+                this._backForwardList.splice(previousEntryIndex, 1);
+                --this._currentBackForwardIndex;
+            }
+
+            this._backForwardList.push(scriptOrResource);
+            ++this._currentBackForwardIndex;
+
+            this._updateBackAndForwardButtons();
+        }
+
+        this.visibleView = view;
+
+        if (line) {
+            if (view.revealLine)
+                view.revealLine(line);
+            if (view.highlightLine && shouldHighlightLine)
+                view.highlightLine(line);
+        }
+
+        var option;
+        if (scriptOrResource instanceof WebInspector.Script) {
+            option = scriptOrResource.filesSelectOption;
+            console.assert(option);
+        } else {
+            var url = scriptOrResource.url;
+            var script = this._scriptsForURLsInFilesSelect[url];
+            if (script)
+               option = script.filesSelectOption;
+        }
+
+        if (option)
+            this.filesSelectElement.selectedIndex = option.index;
+    },
+
+    _addScriptToFilesMenu: function(script)
+    {
+        if (script.resource && this._scriptsForURLsInFilesSelect[script.sourceURL])
+            return;
+
+        this._scriptsForURLsInFilesSelect[script.sourceURL] = script;
+
+        var select = this.filesSelectElement;
+
+        // FIXME: Append in some meaningful order.
+        var option = document.createElement("option");
+        option.representedObject = (script.resource || script);
+        option.text = (script.sourceURL ? WebInspector.displayNameForURL(script.sourceURL) : WebInspector.UIString("(program)"));
+        select.appendChild(option);
+
+        script.filesSelectOption = option;
+
+        // Call _showScriptOrResource if the option we just appended ended up being selected.
+        // This will happen for the first item added to the menu.
+        if (select.options[select.selectedIndex] === option)
+            this._showScriptOrResource(option.representedObject);
+    },
+
+    _clearCurrentExecutionLine: function()
+    {
+        if (this._executionSourceFrame)
+            this._executionSourceFrame.executionLine = 0;
+        delete this._executionSourceFrame;
+    },
+
+    _callFrameSelected: function()
+    {
+        this._clearCurrentExecutionLine();
+
+        var callStackPane = this.sidebarPanes.callstack;
+        var currentFrame = callStackPane.selectedCallFrame;
+        if (!currentFrame)
+            return;
+
+        this.sidebarPanes.scopechain.update(currentFrame);
+
+        var scriptOrResource = this._sourceIDMap[currentFrame.sourceID];
+        this._showScriptOrResource(scriptOrResource, currentFrame.line);
+
+        this._executionSourceFrame = this._sourceFrameForScriptOrResource(scriptOrResource);
+        if (this._executionSourceFrame)
+            this._executionSourceFrame.executionLine = currentFrame.line;
+    },
+
+    _changeVisibleFile: function(event)
+    {
+        var select = this.filesSelectElement;
+        this._showScriptOrResource(select.options[select.selectedIndex].representedObject);
+    },
+
+    _startSidebarResizeDrag: function(event)
+    {
+        WebInspector.elementDragStart(this.sidebarElement, this._sidebarResizeDrag.bind(this), this._endSidebarResizeDrag.bind(this), event, "col-resize");
+
+        if (event.target === this.sidebarResizeWidgetElement)
+            this._dragOffset = (event.target.offsetWidth - (event.pageX - event.target.totalOffsetLeft));
+        else
+            this._dragOffset = 0;
+    },
+
+    _endSidebarResizeDrag: function(event)
+    {
+        WebInspector.elementDragEnd(event);
+
+        delete this._dragOffset;
+    },
+
+    _sidebarResizeDrag: function(event)
+    {
+        var x = event.pageX + this._dragOffset;
+        var newWidth = Number.constrain(window.innerWidth - x, Preferences.minScriptsSidebarWidth, window.innerWidth * 0.66);
+
+        this.sidebarElement.style.width = newWidth + "px";
+        this.sidebarButtonsElement.style.width = newWidth + "px";
+        this.viewsContainerElement.style.right = newWidth + "px";
+        this.sidebarResizeWidgetElement.style.right = newWidth + "px";
+        this.sidebarResizeElement.style.right = (newWidth - 3) + "px";
+
+        event.preventDefault();
+    },
+
+    _updatePauseOnExceptionsButton: function()
+    {
+        if (InspectorController.pauseOnExceptions()) {
+            this.pauseOnExceptionButton.title = WebInspector.UIString("Don't pause on exceptions.");
+            this.pauseOnExceptionButton.addStyleClass("toggled-on");
+        } else {
+            this.pauseOnExceptionButton.title = WebInspector.UIString("Pause on exceptions.");
+            this.pauseOnExceptionButton.removeStyleClass("toggled-on");
+        }
+    },
+
+    _updateDebuggerButtons: function()
+    {
+        if (InspectorController.debuggerEnabled()) {
+            this.enableToggleButton.title = WebInspector.UIString("Debugging enabled. Click to disable.");
+            this.enableToggleButton.addStyleClass("toggled-on");
+            this.pauseOnExceptionButton.removeStyleClass("hidden");
+            this.panelEnablerView.visible = false;
+        } else {
+            this.enableToggleButton.title = WebInspector.UIString("Debugging disabled. Click to enable.");
+            this.enableToggleButton.removeStyleClass("toggled-on");
+            this.pauseOnExceptionButton.addStyleClass("hidden");
+            this.panelEnablerView.visible = true;
+        }
+
+        this._updatePauseOnExceptionsButton();
+
+        if (this._paused) {
+            this.pauseButton.addStyleClass("paused");
+
+            this.pauseButton.disabled = false;
+            this.stepOverButton.disabled = false;
+            this.stepIntoButton.disabled = false;
+            this.stepOutButton.disabled = false;
+
+            this.debuggerStatusElement.textContent = WebInspector.UIString("Paused");
+        } else {
+            this.pauseButton.removeStyleClass("paused");
+
+            this.pauseButton.disabled = this._waitingToPause;
+            this.stepOverButton.disabled = true;
+            this.stepIntoButton.disabled = true;
+            this.stepOutButton.disabled = true;
+
+            if (this._waitingToPause)
+                this.debuggerStatusElement.textContent = WebInspector.UIString("Pausing");
+            else if (this._stepping)
+                this.debuggerStatusElement.textContent = WebInspector.UIString("Stepping");
+            else
+                this.debuggerStatusElement.textContent = "";
+        }
+    },
+
+    _updateBackAndForwardButtons: function()
+    {
+        this.backButton.disabled = this._currentBackForwardIndex <= 0;
+        this.forwardButton.disabled = this._currentBackForwardIndex >= (this._backForwardList.length - 1);
+    },
+
+    _clearInterface: function()
+    {
+        this.sidebarPanes.callstack.update(null);
+        this.sidebarPanes.scopechain.update(null);
+
+        this._clearCurrentExecutionLine();
+        this._updateDebuggerButtons();
+    },
+
+    _goBack: function()
+    {
+        if (this._currentBackForwardIndex <= 0) {
+            console.error("Can't go back from index " + this._currentBackForwardIndex);
+            return;
+        }
+
+        this._showScriptOrResource(this._backForwardList[--this._currentBackForwardIndex], null, false, true);
+        this._updateBackAndForwardButtons();
+    },
+
+    _goForward: function()
+    {
+        if (this._currentBackForwardIndex >= this._backForwardList.length - 1) {
+            console.error("Can't go forward from index " + this._currentBackForwardIndex);
+            return;
+        }
+
+        this._showScriptOrResource(this._backForwardList[++this._currentBackForwardIndex], null, false, true);
+        this._updateBackAndForwardButtons();
+    },
+
+    _enableDebugging: function()
+    {
+        if (InspectorController.debuggerEnabled())
+            return;
+        this._toggleDebugging();
+    },
+
+    _toggleDebugging: function()
+    {
+        this._paused = false;
+        this._waitingToPause = false;
+        this._stepping = false;
+
+        if (InspectorController.debuggerEnabled())
+            InspectorController.disableDebugger();
+        else
+            InspectorController.enableDebugger();
+    },
+
+    _togglePauseOnExceptions: function()
+    {
+        InspectorController.setPauseOnExceptions(!InspectorController.pauseOnExceptions());
+        this._updatePauseOnExceptionsButton();
+    },
+
+    _togglePause: function()
+    {
+        if (this._paused) {
+            this._paused = false;
+            this._waitingToPause = false;
+            InspectorController.resumeDebugger();
+        } else {
+            this._stepping = false;
+            this._waitingToPause = true;
+            InspectorController.pauseInDebugger();
+        }
+
+        this._clearInterface();
+    },
+
+    _stepOverClicked: function()
+    {
+        this._paused = false;
+        this._stepping = true;
+
+        this._clearInterface();
+
+        InspectorController.stepOverStatementInDebugger();
+    },
+
+    _stepIntoClicked: function()
+    {
+        this._paused = false;
+        this._stepping = true;
+
+        this._clearInterface();
+
+        InspectorController.stepIntoStatementInDebugger();
+    },
+
+    _stepOutClicked: function()
+    {
+        this._paused = false;
+        this._stepping = true;
+
+        this._clearInterface();
+
+        InspectorController.stepOutOfFunctionInDebugger();
+    }
+}
+
+WebInspector.ScriptsPanel.prototype.__proto__ = WebInspector.Panel.prototype;
diff --git a/resources/Inspector/SidebarPane.js b/resources/Inspector/SidebarPane.js
new file mode 100644
index 0000000..af9e5f9
--- /dev/null
+++ b/resources/Inspector/SidebarPane.js
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+WebInspector.SidebarPane = function(title)
+{
+    this.element = document.createElement("div");
+    this.element.className = "pane";
+
+    this.titleElement = document.createElement("div");
+    this.titleElement.className = "title";
+    this.titleElement.addEventListener("click", this.toggleExpanded.bind(this), false);
+
+    this.bodyElement = document.createElement("div");
+    this.bodyElement.className = "body";
+
+    this.element.appendChild(this.titleElement);
+    this.element.appendChild(this.bodyElement);
+
+    this.title = title;
+    this.growbarVisible = false;
+    this.expanded = false;
+}
+
+WebInspector.SidebarPane.prototype = {
+    get title()
+    {
+        return this._title;
+    },
+
+    set title(x)
+    {
+        if (this._title === x)
+            return;
+        this._title = x;
+        this.titleElement.textContent = x;
+    },
+
+    get growbarVisible()
+    {
+        return this._growbarVisible;
+    },
+
+    set growbarVisible(x)
+    {
+        if (this._growbarVisible === x)
+            return;
+
+        this._growbarVisible = x;
+
+        if (x && !this._growbarElement) {
+            this._growbarElement = document.createElement("div");
+            this._growbarElement.className = "growbar";
+            this.element.appendChild(this._growbarElement);
+        } else if (!x && this._growbarElement) {
+            if (this._growbarElement.parentNode)
+                this._growbarElement.parentNode(this._growbarElement);
+            delete this._growbarElement;
+        }
+    },
+
+    get expanded()
+    {
+        return this._expanded;
+    },
+
+    set expanded(x)
+    {
+        if (x)
+            this.expand();
+        else
+            this.collapse();
+    },
+
+    expand: function()
+    {
+        if (this._expanded)
+            return;
+        this._expanded = true;
+        this.element.addStyleClass("expanded");
+        if (this.onexpand)
+            this.onexpand(this);
+    },
+
+    collapse: function()
+    {
+        if (!this._expanded)
+            return;
+        this._expanded = false;
+        this.element.removeStyleClass("expanded");
+        if (this.oncollapse)
+            this.oncollapse(this);
+    },
+
+    toggleExpanded: function()
+    {
+        this.expanded = !this.expanded;
+    }
+}
+
+WebInspector.SidebarPane.prototype.__proto__ = WebInspector.Object.prototype;
diff --git a/resources/Inspector/SidebarTreeElement.js b/resources/Inspector/SidebarTreeElement.js
new file mode 100644
index 0000000..c08b0ef
--- /dev/null
+++ b/resources/Inspector/SidebarTreeElement.js
@@ -0,0 +1,201 @@
+/*
+ * 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.SidebarSectionTreeElement = function(title, representedObject, hasChildren)
+{
+    TreeElement.call(this, title.escapeHTML(), representedObject || {}, hasChildren);
+}
+
+WebInspector.SidebarSectionTreeElement.prototype = {
+    selectable: false,
+
+    get smallChildren()
+    {
+        return this._smallChildren;
+    },
+
+    set smallChildren(x)
+    {
+        if (this._smallChildren === x)
+            return;
+
+        this._smallChildren = x;
+
+        if (this._smallChildren)
+            this._childrenListNode.addStyleClass("small");
+        else
+            this._childrenListNode.removeStyleClass("small");
+    },
+
+    onattach: function()
+    {
+        this._listItemNode.addStyleClass("sidebar-tree-section");
+    },
+
+    onreveal: function()
+    {
+        if (this.listItemElement)
+            this.listItemElement.scrollIntoViewIfNeeded(false);
+    }
+}
+
+WebInspector.SidebarSectionTreeElement.prototype.__proto__ = TreeElement.prototype;
+
+WebInspector.SidebarTreeElement = function(className, title, subtitle, representedObject, hasChildren)
+{
+    TreeElement.call(this, "", representedObject || {}, hasChildren);
+
+    if (hasChildren) {
+        this.disclosureButton = document.createElement("button");
+        this.disclosureButton.className = "disclosure-button";
+    }
+
+    if (!this.iconElement) {
+        this.iconElement = document.createElement("img");
+        this.iconElement.className = "icon";
+    }
+
+    this.statusElement = document.createElement("div");
+    this.statusElement.className = "status";
+
+    this.titlesElement = document.createElement("div");
+    this.titlesElement.className = "titles";
+
+    this.titleElement = document.createElement("span");
+    this.titleElement.className = "title";
+    this.titlesElement.appendChild(this.titleElement);
+
+    this.subtitleElement = document.createElement("span");
+    this.subtitleElement.className = "subtitle";
+    this.titlesElement.appendChild(this.subtitleElement);
+
+    this.className = className;
+    this.mainTitle = title;
+    this.subtitle = subtitle;
+}
+
+WebInspector.SidebarTreeElement.prototype = {
+    get small()
+    {
+        return this._small;
+    },
+
+    set small(x)
+    {
+        this._small = x;
+
+        if (this._listItemNode) {
+            if (this._small)
+                this._listItemNode.addStyleClass("small");
+            else
+                this._listItemNode.removeStyleClass("small");
+        }
+    },
+
+    get mainTitle()
+    {
+        return this._mainTitle;
+    },
+
+    set mainTitle(x)
+    {
+        this._mainTitle = x;
+        this.refreshTitles();
+    },
+
+    get subtitle()
+    {
+        return this._subtitle;
+    },
+
+    set subtitle(x)
+    {
+        this._subtitle = x;
+        this.refreshTitles();
+    },
+
+    get bubbleText()
+    {
+        return this._bubbleText;
+    },
+
+    set bubbleText(x)
+    {
+        if (!this.bubbleElement) {
+            this.bubbleElement = document.createElement("div");
+            this.bubbleElement.className = "bubble";
+            this.statusElement.appendChild(this.bubbleElement);
+        }
+
+        this._bubbleText = x;
+        this.bubbleElement.textContent = x;
+    },
+
+    refreshTitles: function()
+    {
+        var mainTitle = this.mainTitle;
+        if (this.titleElement.textContent !== mainTitle)
+            this.titleElement.textContent = mainTitle;
+
+        var subtitle = this.subtitle;
+        if (subtitle) {
+            if (this.subtitleElement.textContent !== subtitle)
+                this.subtitleElement.textContent = subtitle;
+            this.titlesElement.removeStyleClass("no-subtitle");
+        } else
+            this.titlesElement.addStyleClass("no-subtitle");
+    },
+
+    isEventWithinDisclosureTriangle: function(event)
+    {
+        return event.target === this.disclosureButton;
+    },
+
+    onattach: function()
+    {
+        this._listItemNode.addStyleClass("sidebar-tree-item");
+
+        if (this.className)
+            this._listItemNode.addStyleClass(this.className);
+
+        if (this.small)
+            this._listItemNode.addStyleClass("small");
+
+        if (this.hasChildren && this.disclosureButton)
+            this._listItemNode.appendChild(this.disclosureButton);
+
+        this._listItemNode.appendChild(this.iconElement);
+        this._listItemNode.appendChild(this.statusElement);
+        this._listItemNode.appendChild(this.titlesElement);
+    },
+
+    onreveal: function()
+    {
+        if (this._listItemNode)
+            this._listItemNode.scrollIntoViewIfNeeded(false);
+    }
+}
+
+WebInspector.SidebarTreeElement.prototype.__proto__ = TreeElement.prototype;
diff --git a/resources/Inspector/SourceView.js b/resources/Inspector/SourceView.js
new file mode 100644
index 0000000..309027e
--- /dev/null
+++ b/resources/Inspector/SourceView.js
@@ -0,0 +1,303 @@
+/*
+ * 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.SourceView = function(resource)
+{
+    // Set the sourceFrame first since WebInspector.ResourceView will set headersVisible
+    // and our override of headersVisible needs the sourceFrame.
+    this.sourceFrame = new WebInspector.SourceFrame(null, this._addBreakpoint.bind(this));
+
+    WebInspector.ResourceView.call(this, resource);
+
+    resource.addEventListener("finished", this._resourceLoadingFinished, this);
+
+    this.element.addStyleClass("source");
+
+    this._frameNeedsSetup = true;
+
+    this.contentElement.appendChild(this.sourceFrame.element);
+
+    var gutterElement = document.createElement("div");
+    gutterElement.className = "webkit-line-gutter-backdrop";
+    this.element.appendChild(gutterElement);
+}
+
+WebInspector.SourceView.prototype = {
+    set headersVisible(x)
+    {
+        if (x === this._headersVisible)
+            return;
+
+        var superSetter = WebInspector.ResourceView.prototype.__lookupSetter__("headersVisible");
+        if (superSetter)
+            superSetter.call(this, x);
+
+        this.sourceFrame.autoSizesToFitContentHeight = x;
+    },
+
+    show: function(parentElement)
+    {
+        WebInspector.ResourceView.prototype.show.call(this, parentElement);
+        this.setupSourceFrameIfNeeded();
+    },
+
+    hide: function()
+    {
+        WebInspector.View.prototype.hide.call(this);
+        this._currentSearchResultIndex = -1;
+    },
+
+    resize: function()
+    {
+        if (this.sourceFrame.autoSizesToFitContentHeight)
+            this.sourceFrame.sizeToFitContentHeight();
+    },
+
+    detach: function()
+    {
+        WebInspector.ResourceView.prototype.detach.call(this);
+
+        // FIXME: We need to mark the frame for setup on detach because the frame DOM is cleared
+        // when it is removed from the document. Is this a bug?
+        this._frameNeedsSetup = true;
+        this._sourceFrameSetup = false;
+    },
+
+    setupSourceFrameIfNeeded: function()
+    {
+        if (!this._frameNeedsSetup)
+            return;
+
+        this.attach();
+
+        if (!InspectorController.addResourceSourceToFrame(this.resource.identifier, this.sourceFrame.element))
+            return;
+
+        delete this._frameNeedsSetup;
+
+        if (this.resource.type === WebInspector.Resource.Type.Script) {
+            this.sourceFrame.addEventListener("syntax highlighting complete", this._syntaxHighlightingComplete, this);
+            this.sourceFrame.syntaxHighlightJavascript();
+        } else
+            this._sourceFrameSetupFinished();
+    },
+
+    _resourceLoadingFinished: function(event)
+    {
+        this._frameNeedsSetup = true;
+        this._sourceFrameSetup = false;
+        if (this.visible)
+            this.setupSourceFrameIfNeeded();
+        this.resource.removeEventListener("finished", this._resourceLoadingFinished, this);
+    },
+
+    _addBreakpoint: function(line)
+    {
+        var sourceID = null;
+        var closestStartingLine = 0;
+        var scripts = this.resource.scripts;
+        for (var i = 0; i < scripts.length; ++i) {
+            var script = scripts[i];
+            if (script.startingLine <= line && script.startingLine >= closestStartingLine) {
+                closestStartingLine = script.startingLine;
+                sourceID = script.sourceID;
+            }
+        }
+
+        if (WebInspector.panels.scripts) {
+            var breakpoint = new WebInspector.Breakpoint(this.resource.url, line, sourceID);
+            WebInspector.panels.scripts.addBreakpoint(breakpoint);
+        }
+    },
+
+    // The rest of the methods in this prototype need to be generic enough to work with a ScriptView.
+    // The ScriptView prototype pulls these methods into it's prototype to avoid duplicate code.
+
+    searchCanceled: function()
+    {
+        this._currentSearchResultIndex = -1;
+        this._searchResults = [];
+        delete this._delayedFindSearchMatches;
+    },
+
+    performSearch: function(query, finishedCallback)
+    {
+        // Call searchCanceled since it will reset everything we need before doing a new search.
+        this.searchCanceled();
+
+        var lineQueryRegex = /(^|\s)(?:#|line:\s*)(\d+)(\s|$)/i;
+        var lineQueryMatch = query.match(lineQueryRegex);
+        if (lineQueryMatch) {
+            var lineToSearch = parseInt(lineQueryMatch[2]);
+
+            // If there was a space before and after the line query part, replace with a space.
+            // Otherwise replace with an empty string to eat the prefix or postfix space.
+            var lineQueryReplacement = (lineQueryMatch[1] && lineQueryMatch[3] ? " " : "");
+            var filterlessQuery = query.replace(lineQueryRegex, lineQueryReplacement);
+        }
+
+        this._searchFinishedCallback = finishedCallback;
+
+        function findSearchMatches(query, finishedCallback)
+        {
+            if (isNaN(lineToSearch)) {
+                // Search the whole document since there was no line to search.
+                this._searchResults = (InspectorController.search(this.sourceFrame.element.contentDocument, query) || []);
+            } else {
+                var sourceRow = this.sourceFrame.sourceRow(lineToSearch);
+                if (sourceRow) {
+                    if (filterlessQuery) {
+                        // There is still a query string, so search for that string in the line.
+                        this._searchResults = (InspectorController.search(sourceRow, filterlessQuery) || []);
+                    } else {
+                        // Match the whole line, since there was no remaining query string to match.
+                        var rowRange = this.sourceFrame.element.contentDocument.createRange();
+                        rowRange.selectNodeContents(sourceRow);
+                        this._searchResults = [rowRange];
+                    }
+                }
+
+                // Attempt to search for the whole query, just incase it matches a color like "#333".
+                var wholeQueryMatches = InspectorController.search(this.sourceFrame.element.contentDocument, query);
+                if (wholeQueryMatches)
+                    this._searchResults = this._searchResults.concat(wholeQueryMatches);
+            }
+
+            if (this._searchResults)
+                finishedCallback(this, this._searchResults.length);
+        }
+
+        if (!this._sourceFrameSetup) {
+            // The search is performed in _sourceFrameSetupFinished by calling _delayedFindSearchMatches.
+            this._delayedFindSearchMatches = findSearchMatches.bind(this, query, finishedCallback);
+            this.setupSourceFrameIfNeeded();
+            return;
+        }
+
+        findSearchMatches.call(this, query, finishedCallback);
+    },
+
+    jumpToFirstSearchResult: function()
+    {
+        if (!this._searchResults || !this._searchResults.length)
+            return;
+        this._currentSearchResultIndex = 0;
+        this._jumpToSearchResult(this._currentSearchResultIndex);
+    },
+
+    jumpToLastSearchResult: function()
+    {
+        if (!this._searchResults || !this._searchResults.length)
+            return;
+        this._currentSearchResultIndex = (this._searchResults.length - 1);
+        this._jumpToSearchResult(this._currentSearchResultIndex);
+    },
+
+    jumpToNextSearchResult: function()
+    {
+        if (!this._searchResults || !this._searchResults.length)
+            return;
+        if (++this._currentSearchResultIndex >= this._searchResults.length)
+            this._currentSearchResultIndex = 0;
+        this._jumpToSearchResult(this._currentSearchResultIndex);
+    },
+
+    jumpToPreviousSearchResult: function()
+    {
+        if (!this._searchResults || !this._searchResults.length)
+            return;
+        if (--this._currentSearchResultIndex < 0)
+            this._currentSearchResultIndex = (this._searchResults.length - 1);
+        this._jumpToSearchResult(this._currentSearchResultIndex);
+    },
+
+    showingFirstSearchResult: function()
+    {
+        return (this._currentSearchResultIndex === 0);
+    },
+
+    showingLastSearchResult: function()
+    {
+        return (this._searchResults && this._currentSearchResultIndex === (this._searchResults.length - 1));
+    },
+
+    revealLine: function(lineNumber)
+    {
+        this.setupSourceFrameIfNeeded();
+        this.sourceFrame.revealLine(lineNumber);
+    },
+
+    highlightLine: function(lineNumber)
+    {
+        this.setupSourceFrameIfNeeded();
+        this.sourceFrame.highlightLine(lineNumber);
+    },
+
+    addMessage: function(msg)
+    {
+        this.sourceFrame.addMessage(msg);
+    },
+
+    clearMessages: function()
+    {
+        this.sourceFrame.clearMessages();
+    },
+
+    _jumpToSearchResult: function(index)
+    {
+        var foundRange = this._searchResults[index];
+        if (!foundRange)
+            return;
+
+        var selection = window.getSelection();
+        selection.removeAllRanges();
+        selection.addRange(foundRange);
+
+        if (foundRange.startContainer.scrollIntoViewIfNeeded)
+            foundRange.startContainer.scrollIntoViewIfNeeded(true);
+        else if (foundRange.startContainer.parentNode)
+            foundRange.startContainer.parentNode.scrollIntoViewIfNeeded(true);
+    },
+
+    _sourceFrameSetupFinished: function()
+    {
+        this._sourceFrameSetup = true;
+        if (this._delayedFindSearchMatches) {
+            this._delayedFindSearchMatches();
+            delete this._delayedFindSearchMatches;
+        }
+    },
+
+    _syntaxHighlightingComplete: function(event)
+    {
+        this._sourceFrameSetupFinished();
+        this.sourceFrame.removeEventListener("syntax highlighting complete", null, this);
+    }
+}
+
+WebInspector.SourceView.prototype.__proto__ = WebInspector.ResourceView.prototype;
diff --git a/resources/Inspector/StylesSidebarPane.js b/resources/Inspector/StylesSidebarPane.js
new file mode 100644
index 0000000..f0a9afb
--- /dev/null
+++ b/resources/Inspector/StylesSidebarPane.js
@@ -0,0 +1,927 @@
+/*
+ * 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.
+ */
+
+WebInspector.StylesSidebarPane = function()
+{
+    WebInspector.SidebarPane.call(this, WebInspector.UIString("Styles"));
+}
+
+WebInspector.StylesSidebarPane.prototype = {
+    update: function(node, editedSection, forceUpdate)
+    {
+        var refresh = false;
+
+        if (forceUpdate)
+            delete this.node;
+
+        if (!forceUpdate && (!node || node === this.node))
+            refresh = true;
+
+        if (node && node.nodeType === Node.TEXT_NODE && node.parentNode)
+            node = node.parentNode;
+
+        if (node && node.nodeType !== Node.ELEMENT_NODE)
+            node = null;
+
+        if (node)
+            this.node = node;
+        else
+            node = this.node;
+
+        var body = this.bodyElement;
+        if (!refresh || !node) {
+            body.removeChildren();
+            this.sections = [];
+        }
+
+        if (!node)
+            return;
+
+        var styleRules = [];
+
+        if (refresh) {
+            for (var i = 0; i < this.sections.length; ++i) {
+                var section = this.sections[i];
+                if (section.computedStyle)
+                    section.styleRule.style = node.ownerDocument.defaultView.getComputedStyle(node);
+                var styleRule = { section: section, style: section.styleRule.style, computedStyle: section.computedStyle };
+                styleRules.push(styleRule);
+            }
+        } else {
+            var computedStyle = node.ownerDocument.defaultView.getComputedStyle(node);
+            styleRules.push({ computedStyle: true, selectorText: WebInspector.UIString("Computed Style"), style: computedStyle, editable: false });
+
+            var nodeName = node.nodeName.toLowerCase();
+            for (var i = 0; i < node.attributes.length; ++i) {
+                var attr = node.attributes[i];
+                if (attr.style) {
+                    var attrStyle = { style: attr.style, editable: false };
+                    attrStyle.subtitle = WebInspector.UIString("element’s “%s” attribute", attr.name);
+                    attrStyle.selectorText = nodeName + "[" + attr.name;
+                    if (attr.value.length)
+                        attrStyle.selectorText += "=" + attr.value;
+                    attrStyle.selectorText += "]";
+                    styleRules.push(attrStyle);
+                }
+            }
+
+            if (node.style && (node.style.length || Object.hasProperties(node.style.__disabledProperties))) {
+                var inlineStyle = { selectorText: WebInspector.UIString("Inline Style Attribute"), style: node.style };
+                inlineStyle.subtitle = WebInspector.UIString("element’s “%s” attribute", "style");
+                styleRules.push(inlineStyle);
+            }
+
+            var matchedStyleRules = node.ownerDocument.defaultView.getMatchedCSSRules(node, "", !Preferences.showUserAgentStyles);
+            if (matchedStyleRules) {
+                // Add rules in reverse order to match the cascade order.
+                for (var i = (matchedStyleRules.length - 1); i >= 0; --i) {
+                    var rule = matchedStyleRules[i];
+                    styleRules.push({ style: rule.style, selectorText: rule.selectorText, parentStyleSheet: rule.parentStyleSheet });
+                }
+            }
+        }
+
+        function deleteDisabledProperty(style, name)
+        {
+            if (!style || !name)
+                return;
+            if (style.__disabledPropertyValues)
+                delete style.__disabledPropertyValues[name];
+            if (style.__disabledPropertyPriorities)
+                delete style.__disabledPropertyPriorities[name];
+            if (style.__disabledProperties)
+                delete style.__disabledProperties[name];
+        }
+
+        var usedProperties = {};
+        var disabledComputedProperties = {};
+        var priorityUsed = false;
+
+        // Walk the style rules and make a list of all used and overloaded properties.
+        for (var i = 0; i < styleRules.length; ++i) {
+            var styleRule = styleRules[i];
+            if (styleRule.computedStyle)
+                continue;
+
+            styleRule.usedProperties = {};
+
+            var style = styleRule.style;
+            for (var j = 0; j < style.length; ++j) {
+                var name = style[j];
+
+                if (!priorityUsed && style.getPropertyPriority(name).length)
+                    priorityUsed = true;
+
+                // If the property name is already used by another rule then this rule's
+                // property is overloaded, so don't add it to the rule's usedProperties.
+                if (!(name in usedProperties))
+                    styleRule.usedProperties[name] = true;
+
+                if (name === "font") {
+                    // The font property is not reported as a shorthand. Report finding the individual
+                    // properties so they are visible in computed style.
+                    // FIXME: remove this when http://bugs.webkit.org/show_bug.cgi?id=15598 is fixed.
+                    styleRule.usedProperties["font-family"] = true;
+                    styleRule.usedProperties["font-size"] = true;
+                    styleRule.usedProperties["font-style"] = true;
+                    styleRule.usedProperties["font-variant"] = true;
+                    styleRule.usedProperties["font-weight"] = true;
+                    styleRule.usedProperties["line-height"] = true;
+                }
+
+                // Delete any disabled properties, since the property does exist.
+                // This prevents it from showing twice.
+                deleteDisabledProperty(style, name);
+                deleteDisabledProperty(style, style.getPropertyShorthand(name));
+            }
+
+            // Add all the properties found in this style to the used properties list.
+            // Do this here so only future rules are affect by properties used in this rule.
+            for (var name in styleRules[i].usedProperties)
+                usedProperties[name] = true;
+
+            // Remember all disabled properties so they show up in computed style.
+            if (style.__disabledProperties)
+                for (var name in style.__disabledProperties)
+                    disabledComputedProperties[name] = true;
+        }
+
+        if (priorityUsed) {
+            // Walk the properties again and account for !important.
+            var foundPriorityProperties = [];
+
+            // Walk in reverse to match the order !important overrides.
+            for (var i = (styleRules.length - 1); i >= 0; --i) {
+                if (styleRules[i].computedStyle)
+                    continue;
+
+                var style = styleRules[i].style;
+                var uniqueProperties = getUniqueStyleProperties(style);
+                for (var j = 0; j < uniqueProperties.length; ++j) {
+                    var name = uniqueProperties[j];
+                    if (style.getPropertyPriority(name).length) {
+                        if (!(name in foundPriorityProperties))
+                            styleRules[i].usedProperties[name] = true;
+                        else
+                            delete styleRules[i].usedProperties[name];
+                        foundPriorityProperties[name] = true;
+                    } else if (name in foundPriorityProperties)
+                        delete styleRules[i].usedProperties[name];
+                }
+            }
+        }
+
+        if (refresh) {
+            // Walk the style rules and update the sections with new overloaded and used properties.
+            for (var i = 0; i < styleRules.length; ++i) {
+                var styleRule = styleRules[i];
+                var section = styleRule.section;
+                if (styleRule.computedStyle)
+                    section.disabledComputedProperties = disabledComputedProperties;
+                section._usedProperties = (styleRule.usedProperties || usedProperties);
+                section.update((section === editedSection) || styleRule.computedStyle);
+            }
+        } else {
+            // Make a property section for each style rule.
+            for (var i = 0; i < styleRules.length; ++i) {
+                var styleRule = styleRules[i];
+                var subtitle = styleRule.subtitle;
+                delete styleRule.subtitle;
+
+                var computedStyle = styleRule.computedStyle;
+                delete styleRule.computedStyle;
+
+                var ruleUsedProperties = styleRule.usedProperties;
+                delete styleRule.usedProperties;
+
+                var editable = styleRule.editable;
+                delete styleRule.editable;
+
+                // Default editable to true if it was omitted.
+                if (typeof editable === "undefined")
+                    editable = true;
+
+                var section = new WebInspector.StylePropertiesSection(styleRule, subtitle, computedStyle, (ruleUsedProperties || usedProperties), editable);
+                if (computedStyle)
+                    section.disabledComputedProperties = disabledComputedProperties;
+                section.pane = this;
+
+                if (Preferences.styleRulesExpandedState && section.identifier in Preferences.styleRulesExpandedState)
+                    section.expanded = Preferences.styleRulesExpandedState[section.identifier];
+                else if (computedStyle)
+                    section.collapse(true);
+                else
+                    section.expand(true);
+
+                body.appendChild(section.element);
+                this.sections.push(section);
+            }
+        }
+    }
+}
+
+WebInspector.StylesSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype;
+
+WebInspector.StylePropertiesSection = function(styleRule, subtitle, computedStyle, usedProperties, editable)
+{
+    WebInspector.PropertiesSection.call(this, styleRule.selectorText);
+
+    this.styleRule = styleRule;
+    this.computedStyle = computedStyle;
+    this.editable = (editable && !computedStyle);
+
+    // Prevent editing the user agent and user rules.
+    var isUserAgent = this.styleRule.parentStyleSheet && !this.styleRule.parentStyleSheet.ownerNode && !this.styleRule.parentStyleSheet.href;
+    var isUser = this.styleRule.parentStyleSheet && this.styleRule.parentStyleSheet.ownerNode && this.styleRule.parentStyleSheet.ownerNode.nodeName == '#document';
+    if (isUserAgent || isUser)
+        this.editable = false;
+
+    this._usedProperties = usedProperties;
+
+    if (computedStyle) {
+        this.element.addStyleClass("computed-style");
+
+        if (Preferences.showInheritedComputedStyleProperties)
+            this.element.addStyleClass("show-inherited");
+
+        var showInheritedLabel = document.createElement("label");
+        var showInheritedInput = document.createElement("input");
+        showInheritedInput.type = "checkbox";
+        showInheritedInput.checked = Preferences.showInheritedComputedStyleProperties;
+
+        var computedStyleSection = this;
+        var showInheritedToggleFunction = function(event) {
+            Preferences.showInheritedComputedStyleProperties = showInheritedInput.checked;
+            if (Preferences.showInheritedComputedStyleProperties)
+                computedStyleSection.element.addStyleClass("show-inherited");
+            else
+                computedStyleSection.element.removeStyleClass("show-inherited");
+            event.stopPropagation();
+        };
+
+        showInheritedLabel.addEventListener("click", showInheritedToggleFunction, false);
+
+        showInheritedLabel.appendChild(showInheritedInput);
+        showInheritedLabel.appendChild(document.createTextNode(WebInspector.UIString("Show inherited")));
+        this.subtitleElement.appendChild(showInheritedLabel);
+    } else {
+        if (!subtitle) {
+            if (this.styleRule.parentStyleSheet && this.styleRule.parentStyleSheet.href) {
+                var url = this.styleRule.parentStyleSheet.href;
+                subtitle = WebInspector.linkifyURL(url, WebInspector.displayNameForURL(url));
+                this.subtitleElement.addStyleClass("file");
+            } else if (isUserAgent)
+                subtitle = WebInspector.UIString("user agent stylesheet");
+            else if (isUser)
+                subtitle = WebInspector.UIString("user stylesheet");
+            else
+                subtitle = WebInspector.UIString("inline stylesheet");
+        }
+
+        this.subtitle = subtitle;
+    }
+
+    this.identifier = styleRule.selectorText;
+    if (this.subtitle)
+        this.identifier += ":" + this.subtitleElement.textContent;
+}
+
+WebInspector.StylePropertiesSection.prototype = {
+    get usedProperties()
+    {
+        return this._usedProperties || {};
+    },
+
+    set usedProperties(x)
+    {
+        this._usedProperties = x;
+        this.update();
+    },
+
+    expand: function(dontRememberState)
+    {
+        WebInspector.PropertiesSection.prototype.expand.call(this);
+        if (dontRememberState)
+            return;
+
+        if (!Preferences.styleRulesExpandedState)
+            Preferences.styleRulesExpandedState = {};
+        Preferences.styleRulesExpandedState[this.identifier] = true;
+    },
+
+    collapse: function(dontRememberState)
+    {
+        WebInspector.PropertiesSection.prototype.collapse.call(this);
+        if (dontRememberState)
+            return;
+
+        if (!Preferences.styleRulesExpandedState)
+            Preferences.styleRulesExpandedState = {};
+        Preferences.styleRulesExpandedState[this.identifier] = false;
+    },
+
+    isPropertyInherited: function(property)
+    {
+        if (!this.computedStyle || !this._usedProperties)
+            return false;
+        // These properties should always show for Computed Style.
+        var alwaysShowComputedProperties = { "display": true, "height": true, "width": true };
+        return !(property in this.usedProperties) && !(property in alwaysShowComputedProperties) && !(property in this.disabledComputedProperties);
+    },
+
+    isPropertyOverloaded: function(property, shorthand)
+    {
+        if (this.computedStyle || !this._usedProperties)
+            return false;
+
+        var used = (property in this.usedProperties);
+        if (used || !shorthand)
+            return !used;
+
+        // Find out if any of the individual longhand properties of the shorthand
+        // are used, if none are then the shorthand is overloaded too.
+        var longhandProperties = getLonghandProperties(this.styleRule.style, property);
+        for (var j = 0; j < longhandProperties.length; ++j) {
+            var individualProperty = longhandProperties[j];
+            if (individualProperty in this.usedProperties)
+                return false;
+        }
+
+        return true;
+    },
+
+    update: function(full)
+    {
+        if (full || this.computedStyle) {
+            this.propertiesTreeOutline.removeChildren();
+            this.populated = false;
+        } else {
+            var child = this.propertiesTreeOutline.children[0];
+            while (child) {
+                child.overloaded = this.isPropertyOverloaded(child.name, child.shorthand);
+                child = child.traverseNextTreeElement(false, null, true);
+            }
+        }
+    },
+
+    onpopulate: function()
+    {
+        var style = this.styleRule.style;
+
+        var foundShorthands = {};
+        var uniqueProperties = getUniqueStyleProperties(style);
+        var disabledProperties = style.__disabledPropertyValues || {};
+
+        for (var name in disabledProperties)
+            uniqueProperties.push(name);
+
+        uniqueProperties.sort();
+
+        for (var i = 0; i < uniqueProperties.length; ++i) {
+            var name = uniqueProperties[i];
+            var disabled = name in disabledProperties;
+            if (!disabled && this.disabledComputedProperties && !(name in this.usedProperties) && name in this.disabledComputedProperties)
+                disabled = true;
+
+            var shorthand = !disabled ? style.getPropertyShorthand(name) : null;
+
+            if (shorthand && shorthand in foundShorthands)
+                continue;
+
+            if (shorthand) {
+                foundShorthands[shorthand] = true;
+                name = shorthand;
+            }
+
+            var isShorthand = (shorthand ? true : false);
+            var inherited = this.isPropertyInherited(name);
+            var overloaded = this.isPropertyOverloaded(name, isShorthand);
+
+            var item = new WebInspector.StylePropertyTreeElement(style, name, isShorthand, inherited, overloaded, disabled);
+            this.propertiesTreeOutline.appendChild(item);
+        }
+    }
+}
+
+WebInspector.StylePropertiesSection.prototype.__proto__ = WebInspector.PropertiesSection.prototype;
+
+WebInspector.StylePropertyTreeElement = function(style, name, shorthand, inherited, overloaded, disabled)
+{
+    this.style = style;
+    this.name = name;
+    this.shorthand = shorthand;
+    this._inherited = inherited;
+    this._overloaded = overloaded;
+    this._disabled = disabled;
+
+    // Pass an empty title, the title gets made later in onattach.
+    TreeElement.call(this, "", null, shorthand);
+}
+
+WebInspector.StylePropertyTreeElement.prototype = {
+    get inherited()
+    {
+        return this._inherited;
+    },
+
+    set inherited(x)
+    {
+        if (x === this._inherited)
+            return;
+        this._inherited = x;
+        this.updateState();
+    },
+
+    get overloaded()
+    {
+        return this._overloaded;
+    },
+
+    set overloaded(x)
+    {
+        if (x === this._overloaded)
+            return;
+        this._overloaded = x;
+        this.updateState();
+    },
+
+    get disabled()
+    {
+        return this._disabled;
+    },
+
+    set disabled(x)
+    {
+        if (x === this._disabled)
+            return;
+        this._disabled = x;
+        this.updateState();
+    },
+
+    get priority()
+    {
+        if (this.disabled && this.style.__disabledPropertyPriorities && this.name in this.style.__disabledPropertyPriorities)
+            return this.style.__disabledPropertyPriorities[this.name];
+        return (this.shorthand ? getShorthandPriority(this.style, this.name) : this.style.getPropertyPriority(this.name));
+    },
+
+    get value()
+    {
+        if (this.disabled && this.style.__disabledPropertyValues && this.name in this.style.__disabledPropertyValues)
+            return this.style.__disabledPropertyValues[this.name];
+        return (this.shorthand ? getShorthandValue(this.style, this.name) : this.style.getPropertyValue(this.name));
+    },
+
+    onattach: function()
+    {
+        this.updateTitle();
+    },
+
+    updateTitle: function()
+    {
+        // "Nicknames" for some common values that are easier to read.
+        var valueNicknames = {
+            "rgb(0, 0, 0)": "black",
+            "#000": "black",
+            "#000000": "black",
+            "rgb(255, 255, 255)": "white",
+            "#fff": "white",
+            "#ffffff": "white",
+            "#FFF": "white",
+            "#FFFFFF": "white",
+            "rgba(0, 0, 0, 0)": "transparent",
+            "rgb(255, 0, 0)": "red",
+            "rgb(0, 255, 0)": "lime",
+            "rgb(0, 0, 255)": "blue",
+            "rgb(255, 255, 0)": "yellow",
+            "rgb(255, 0, 255)": "magenta",
+            "rgb(0, 255, 255)": "cyan"
+        };
+
+        var priority = this.priority;
+        var value = this.value;
+        var htmlValue = value;
+
+        if (priority && !priority.length)
+            delete priority;
+        if (priority)
+            priority = "!" + priority;
+
+        if (value) {
+            var urls = value.match(/url\([^)]+\)/);
+            if (urls) {
+                for (var i = 0; i < urls.length; ++i) {
+                    var url = urls[i].substring(4, urls[i].length - 1);
+                    htmlValue = htmlValue.replace(urls[i], "url(" + WebInspector.linkifyURL(url) + ")");
+                }
+            } else {
+                if (value in valueNicknames)
+                    htmlValue = valueNicknames[value];
+                htmlValue = htmlValue.escapeHTML();
+            }
+        } else
+            htmlValue = value = "";
+
+        this.updateState();
+
+        var enabledCheckboxElement = document.createElement("input");
+        enabledCheckboxElement.className = "enabled-button";
+        enabledCheckboxElement.type = "checkbox";
+        enabledCheckboxElement.checked = !this.disabled;
+        enabledCheckboxElement.addEventListener("change", this.toggleEnabled.bind(this), false);
+
+        var nameElement = document.createElement("span");
+        nameElement.className = "name";
+        nameElement.textContent = this.name;
+
+        var valueElement = document.createElement("span");
+        valueElement.className = "value";
+        valueElement.innerHTML = htmlValue;
+
+        if (priority) {
+            var priorityElement = document.createElement("span");
+            priorityElement.className = "priority";
+            priorityElement.textContent = priority;
+        }
+
+        this.listItemElement.removeChildren();
+
+        // Append the checkbox for root elements of an editable section.
+        if (this.treeOutline.section && this.treeOutline.section.editable && this.parent.root)
+            this.listItemElement.appendChild(enabledCheckboxElement);
+        this.listItemElement.appendChild(nameElement);
+        this.listItemElement.appendChild(document.createTextNode(": "));
+        this.listItemElement.appendChild(valueElement);
+
+        if (priorityElement) {
+            this.listItemElement.appendChild(document.createTextNode(" "));
+            this.listItemElement.appendChild(priorityElement);
+        }
+
+        this.listItemElement.appendChild(document.createTextNode(";"));
+
+        if (value) {
+            // FIXME: this dosen't catch keyword based colors like black and white
+            var colors = value.match(/((rgb|hsl)a?\([^)]+\))|(#[0-9a-fA-F]{6})|(#[0-9a-fA-F]{3})/g);
+            if (colors) {
+                var colorsLength = colors.length;
+                for (var i = 0; i < colorsLength; ++i) {
+                    var swatchElement = document.createElement("span");
+                    swatchElement.className = "swatch";
+                    swatchElement.style.setProperty("background-color", colors[i]);
+                    this.listItemElement.appendChild(swatchElement);
+                }
+            }
+        }
+
+        this.tooltip = this.name + ": " + (valueNicknames[value] || value) + (priority ? " " + priority : "");
+    },
+
+    updateAll: function(updateAllRules)
+    {
+        if (updateAllRules && this.treeOutline.section && this.treeOutline.section.pane)
+            this.treeOutline.section.pane.update(null, this.treeOutline.section);
+        else if (this.treeOutline.section)
+            this.treeOutline.section.update(true);
+        else
+            this.updateTitle(); // FIXME: this will not show new properties. But we don't hit his case yet.
+    },
+
+    toggleEnabled: function(event)
+    {
+        var disabled = !event.target.checked;
+
+        if (disabled) {
+            if (!this.style.__disabledPropertyValues || !this.style.__disabledPropertyPriorities) {
+                var inspectedWindow = InspectorController.inspectedWindow();
+                this.style.__disabledProperties = new inspectedWindow.Object;
+                this.style.__disabledPropertyValues = new inspectedWindow.Object;
+                this.style.__disabledPropertyPriorities = new inspectedWindow.Object;
+            }
+
+            this.style.__disabledPropertyValues[this.name] = this.value;
+            this.style.__disabledPropertyPriorities[this.name] = this.priority;
+
+            if (this.shorthand) {
+                var longhandProperties = getLonghandProperties(this.style, this.name);
+                for (var i = 0; i < longhandProperties.length; ++i) {
+                    this.style.__disabledProperties[longhandProperties[i]] = true;
+                    this.style.removeProperty(longhandProperties[i]);
+                }
+            } else {
+                this.style.__disabledProperties[this.name] = true;
+                this.style.removeProperty(this.name);
+            }
+        } else {
+            this.style.setProperty(this.name, this.value, this.priority);
+            delete this.style.__disabledProperties[this.name];
+            delete this.style.__disabledPropertyValues[this.name];
+            delete this.style.__disabledPropertyPriorities[this.name];
+        }
+
+        // Set the disabled property here, since the code above replies on it not changing
+        // until after the value and priority are retrieved.
+        this.disabled = disabled;
+
+        if (this.treeOutline.section && this.treeOutline.section.pane)
+            this.treeOutline.section.pane.dispatchEventToListeners("style property toggled");
+
+        this.updateAll(true);
+    },
+
+    updateState: function()
+    {
+        if (!this.listItemElement)
+            return;
+
+        if (this.style.isPropertyImplicit(this.name) || this.value === "initial")
+            this.listItemElement.addStyleClass("implicit");
+        else
+            this.listItemElement.removeStyleClass("implicit");
+
+        if (this.inherited)
+            this.listItemElement.addStyleClass("inherited");
+        else
+            this.listItemElement.removeStyleClass("inherited");
+
+        if (this.overloaded)
+            this.listItemElement.addStyleClass("overloaded");
+        else
+            this.listItemElement.removeStyleClass("overloaded");
+
+        if (this.disabled)
+            this.listItemElement.addStyleClass("disabled");
+        else
+            this.listItemElement.removeStyleClass("disabled");
+    },
+
+    onpopulate: function()
+    {
+        // Only populate once and if this property is a shorthand.
+        if (this.children.length || !this.shorthand)
+            return;
+
+        var longhandProperties = getLonghandProperties(this.style, this.name);
+        for (var i = 0; i < longhandProperties.length; ++i) {
+            var name = longhandProperties[i];
+
+            if (this.treeOutline.section) {
+                var inherited = this.treeOutline.section.isPropertyInherited(name);
+                var overloaded = this.treeOutline.section.isPropertyOverloaded(name);
+            }
+
+            var item = new WebInspector.StylePropertyTreeElement(this.style, name, false, inherited, overloaded);
+            this.appendChild(item);
+        }
+    },
+
+    ondblclick: function(element, event)
+    {
+        this.startEditing(event.target);
+    },
+
+    startEditing: function(selectElement)
+    {
+        // FIXME: we don't allow editing of longhand properties under a shorthand right now.
+        if (this.parent.shorthand)
+            return;
+
+        if (WebInspector.isBeingEdited(this.listItemElement) || (this.treeOutline.section && !this.treeOutline.section.editable))
+            return;
+
+        var context = { expanded: this.expanded, hasChildren: this.hasChildren };
+
+        // Lie about our children to prevent expanding on double click and to collapse shorthands.
+        this.hasChildren = false;
+
+        if (!selectElement)
+            selectElement = this.listItemElement;
+
+        this.listItemElement.handleKeyEvent = this.editingKeyDown.bind(this);
+
+        WebInspector.startEditing(this.listItemElement, this.editingCommitted.bind(this), this.editingCancelled.bind(this), context);
+        window.getSelection().setBaseAndExtent(selectElement, 0, selectElement, 1);
+    },
+
+    editingKeyDown: function(event)
+    {
+        var arrowKeyPressed = (event.keyIdentifier === "Up" || event.keyIdentifier === "Down");
+        var pageKeyPressed = (event.keyIdentifier === "PageUp" || event.keyIdentifier === "PageDown");
+        if (!arrowKeyPressed && !pageKeyPressed)
+            return;
+
+        var selection = window.getSelection();
+        if (!selection.rangeCount)
+            return;
+
+        var selectionRange = selection.getRangeAt(0);
+        if (selectionRange.commonAncestorContainer !== this.listItemElement && !selectionRange.commonAncestorContainer.isDescendant(this.listItemElement))
+            return;
+
+        const styleValueDelimeters = " \t\n\"':;,/()";
+        var wordRange = selectionRange.startContainer.rangeOfWord(selectionRange.startOffset, styleValueDelimeters, this.listItemElement);
+        var wordString = wordRange.toString();
+        var replacementString = wordString;
+
+        var matches = /(.*?)(-?\d+(?:\.\d+)?)(.*)/.exec(wordString);
+        if (matches && matches.length) {
+            var prefix = matches[1];
+            var number = parseFloat(matches[2]);
+            var suffix = matches[3];
+
+            // If the number is near zero or the number is one and the direction will take it near zero.
+            var numberNearZero = (number < 1 && number > -1);
+            if (number === 1 && event.keyIdentifier === "Down")
+                numberNearZero = true;
+            else if (number === -1 && event.keyIdentifier === "Up")
+                numberNearZero = true;
+
+            if (numberNearZero && event.altKey && arrowKeyPressed) {
+                if (event.keyIdentifier === "Down")
+                    number = Math.ceil(number - 1);
+                else
+                    number = Math.floor(number + 1);
+            } else {
+                // Jump by 10 when shift is down or jump by 0.1 when near zero or Alt/Option is down.
+                // Also jump by 10 for page up and down, or by 100 if shift is held with a page key.
+                var changeAmount = 1;
+                if (event.shiftKey && pageKeyPressed)
+                    changeAmount = 100;
+                else if (event.shiftKey || pageKeyPressed)
+                    changeAmount = 10;
+                else if (event.altKey || numberNearZero)
+                    changeAmount = 0.1;
+
+                if (event.keyIdentifier === "Down" || event.keyIdentifier === "PageDown")
+                    changeAmount *= -1;
+
+                // Make the new number and constrain it to a precision of 6, this matches numbers the engine returns.
+                // Use the Number constructor to forget the fixed precision, so 1.100000 will print as 1.1.
+                number = Number((number + changeAmount).toFixed(6));
+            }
+
+            replacementString = prefix + number + suffix;
+        } else {
+            // FIXME: this should cycle through known keywords for the current property name.
+            return;
+        }
+
+        var replacementTextNode = document.createTextNode(replacementString);
+
+        wordRange.deleteContents();
+        wordRange.insertNode(replacementTextNode);
+
+        var finalSelectionRange = document.createRange();
+        finalSelectionRange.setStart(replacementTextNode, 0);
+        finalSelectionRange.setEnd(replacementTextNode, replacementString.length);
+
+        selection.removeAllRanges();
+        selection.addRange(finalSelectionRange);
+
+        event.preventDefault();
+        event.handled = true;
+
+        if (!this.originalCSSText) {
+            // Remember the rule's original CSS text, so it can be restored
+            // if the editing is canceled and before each apply.
+            this.originalCSSText = getStyleTextWithShorthands(this.style);
+        } else {
+            // Restore the original CSS text before applying user changes. This is needed to prevent
+            // new properties from sticking around if the user adds one, then removes it.
+            this.style.cssText = this.originalCSSText;
+        }
+
+        this.applyStyleText(this.listItemElement.textContent);
+    },
+
+    editingEnded: function(context)
+    {
+        this.hasChildren = context.hasChildren;
+        if (context.expanded)
+            this.expand();
+        delete this.listItemElement.handleKeyEvent;
+        delete this.originalCSSText;
+    },
+
+    editingCancelled: function(element, context)
+    {
+        if (this.originalCSSText) {
+            this.style.cssText = this.originalCSSText;
+
+            if (this.treeOutline.section && this.treeOutline.section.pane)
+                this.treeOutline.section.pane.dispatchEventToListeners("style edited");
+
+            this.updateAll();
+        } else
+            this.updateTitle();
+
+        this.editingEnded(context);
+    },
+
+    editingCommitted: function(element, userInput, previousContent, context)
+    {
+        this.editingEnded(context);
+
+        if (userInput === previousContent)
+            return; // nothing changed, so do nothing else
+
+        this.applyStyleText(userInput, true);
+    },
+
+    applyStyleText: function(styleText, updateInterface)
+    {
+        var styleTextLength = styleText.trimWhitespace().length;
+
+        // Create a new element to parse the user input CSS.
+        var parseElement = document.createElement("span");
+        parseElement.setAttribute("style", styleText);
+
+        var tempStyle = parseElement.style;
+        if (tempStyle.length || !styleTextLength) {
+            // The input was parsable or the user deleted everything, so remove the
+            // original property from the real style declaration. If this represents
+            // a shorthand remove all the longhand properties.
+            if (this.shorthand) {
+                var longhandProperties = getLonghandProperties(this.style, this.name);
+                for (var i = 0; i < longhandProperties.length; ++i)
+                    this.style.removeProperty(longhandProperties[i]);
+            } else
+                this.style.removeProperty(this.name);
+        }
+
+        if (!styleTextLength) {
+            if (updateInterface) {
+                // The user deleted the everything, so remove the tree element and update.
+                if (this.treeOutline.section && this.treeOutline.section.pane)
+                    this.treeOutline.section.pane.update();
+                this.parent.removeChild(this);
+            }
+            return;
+        }
+
+        if (!tempStyle.length) {
+            // The user typed something, but it didn't parse. Just abort and restore
+            // the original title for this property.
+            if (updateInterface)
+                this.updateTitle();
+            return;
+        }
+
+        // Iterate of the properties on the test element's style declaration and
+        // add them to the real style declaration. We take care to move shorthands.
+        var foundShorthands = {};
+        var uniqueProperties = getUniqueStyleProperties(tempStyle);
+        for (var i = 0; i < uniqueProperties.length; ++i) {
+            var name = uniqueProperties[i];
+            var shorthand = tempStyle.getPropertyShorthand(name);
+
+            if (shorthand && shorthand in foundShorthands)
+                continue;
+
+            if (shorthand) {
+                var value = getShorthandValue(tempStyle, shorthand);
+                var priority = getShorthandPriority(tempStyle, shorthand);
+                foundShorthands[shorthand] = true;
+            } else {
+                var value = tempStyle.getPropertyValue(name);
+                var priority = tempStyle.getPropertyPriority(name);
+            }
+
+            // Set the property on the real style declaration.
+            this.style.setProperty((shorthand || name), value, priority);
+        }
+
+        if (this.treeOutline.section && this.treeOutline.section.pane)
+            this.treeOutline.section.pane.dispatchEventToListeners("style edited");
+
+        if (updateInterface)
+            this.updateAll(true);
+    }
+}
+
+WebInspector.StylePropertyTreeElement.prototype.__proto__ = TreeElement.prototype;
diff --git a/resources/Inspector/TextPrompt.js b/resources/Inspector/TextPrompt.js
new file mode 100644
index 0000000..61e1b52
--- /dev/null
+++ b/resources/Inspector/TextPrompt.js
@@ -0,0 +1,312 @@
+/*
+ * 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.
+ * 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.TextPrompt = function(element, completions, stopCharacters)
+{
+    this.element = element;
+    this.completions = completions;
+    this.completionStopCharacters = stopCharacters;
+    this.history = [];
+    this.historyOffset = 0;
+}
+
+WebInspector.TextPrompt.prototype = {
+    get text()
+    {
+        return this.element.textContent;
+    },
+
+    set text(x)
+    {
+        if (!x) {
+            // Append a break element instead of setting textContent to make sure the selection is inside the prompt.
+            this.element.removeChildren();
+            this.element.appendChild(document.createElement("br"));
+        } else
+            this.element.textContent = x;
+
+        this.moveCaretToEndOfPrompt();
+    },
+
+    handleKeyEvent: function(event)
+    {
+        switch (event.keyIdentifier) {
+            case "Up":
+                this._upKeyPressed(event);
+                break;
+            case "Down":
+                this._downKeyPressed(event);
+                break;
+            case "U+0009": // Tab
+                this._tabKeyPressed(event);
+                break;
+            case "Right":
+                if (!this.acceptAutoComplete())
+                    this.autoCompleteSoon();
+                break;
+            default:
+                this.clearAutoComplete();
+                this.autoCompleteSoon();
+                break;
+        }
+    },
+
+    acceptAutoComplete: function()
+    {
+        if (!this.autoCompleteElement || !this.autoCompleteElement.parentNode)
+            return false;
+
+        var text = this.autoCompleteElement.textContent;
+        var textNode = document.createTextNode(text);
+        this.autoCompleteElement.parentNode.replaceChild(textNode, this.autoCompleteElement);
+        delete this.autoCompleteElement;
+
+        var finalSelectionRange = document.createRange();
+        finalSelectionRange.setStart(textNode, text.length);
+        finalSelectionRange.setEnd(textNode, text.length);
+
+        var selection = window.getSelection();
+        selection.removeAllRanges();
+        selection.addRange(finalSelectionRange);
+
+        return true;
+    },
+
+    clearAutoComplete: function(includeTimeout)
+    {
+        if (includeTimeout && "_completeTimeout" in this) {
+            clearTimeout(this._completeTimeout);
+            delete this._completeTimeout;
+        }
+
+        if (!this.autoCompleteElement)
+            return;
+
+        if (this.autoCompleteElement.parentNode)
+            this.autoCompleteElement.parentNode.removeChild(this.autoCompleteElement);
+        delete this.autoCompleteElement;
+
+        if (!this._userEnteredRange || !this._userEnteredText)
+            return;
+
+        this._userEnteredRange.deleteContents();
+
+        var userTextNode = document.createTextNode(this._userEnteredText);
+        this._userEnteredRange.insertNode(userTextNode);           
+
+        var selectionRange = document.createRange();
+        selectionRange.setStart(userTextNode, this._userEnteredText.length);
+        selectionRange.setEnd(userTextNode, this._userEnteredText.length);
+
+        var selection = window.getSelection();
+        selection.removeAllRanges();
+        selection.addRange(selectionRange);
+
+        delete this._userEnteredRange;
+        delete this._userEnteredText;
+    },
+
+    autoCompleteSoon: function()
+    {
+        if (!("_completeTimeout" in this))
+            this._completeTimeout = setTimeout(this.complete.bind(this, true), 250);
+    },
+
+    complete: function(auto)
+    {
+        this.clearAutoComplete(true);
+
+        var selection = window.getSelection();
+        if (!selection.rangeCount)
+            return;
+
+        var selectionRange = selection.getRangeAt(0);
+        if (!selectionRange.commonAncestorContainer.isDescendant(this.element))
+            return;
+        if (auto && !this.isCaretAtEndOfPrompt())
+            return;
+
+        var wordPrefixRange = selectionRange.startContainer.rangeOfWord(selectionRange.startOffset, this.completionStopCharacters, this.element, "backward");
+        var completions = this.completions(wordPrefixRange, auto);
+
+        if (!completions || !completions.length)
+            return;
+
+        var fullWordRange = document.createRange();
+        fullWordRange.setStart(wordPrefixRange.startContainer, wordPrefixRange.startOffset);
+        fullWordRange.setEnd(selectionRange.endContainer, selectionRange.endOffset);
+
+        if (completions.length === 1 || selection.isCollapsed || auto) {
+            var completionText = completions[0];
+        } else {
+            var currentText = fullWordRange.toString();
+
+            var foundIndex = null;
+            for (var i = 0; i < completions.length; ++i) {
+                if (completions[i] === currentText)
+                    foundIndex = i;
+            }
+
+            if (foundIndex === null || (foundIndex + 1) >= completions.length)
+                var completionText = completions[0];
+            else
+                var completionText = completions[foundIndex + 1];
+        }
+
+        var wordPrefixLength = wordPrefixRange.toString().length;
+
+        this._userEnteredRange = fullWordRange;
+        this._userEnteredText = fullWordRange.toString();
+
+        fullWordRange.deleteContents();
+
+        var finalSelectionRange = document.createRange();
+
+        if (auto) {
+            var prefixText = completionText.substring(0, wordPrefixLength);
+            var suffixText = completionText.substring(wordPrefixLength);
+
+            var prefixTextNode = document.createTextNode(prefixText);
+            fullWordRange.insertNode(prefixTextNode);           
+
+            this.autoCompleteElement = document.createElement("span");
+            this.autoCompleteElement.className = "auto-complete-text";
+            this.autoCompleteElement.textContent = suffixText;
+
+            prefixTextNode.parentNode.insertBefore(this.autoCompleteElement, prefixTextNode.nextSibling);
+
+            finalSelectionRange.setStart(prefixTextNode, wordPrefixLength);
+            finalSelectionRange.setEnd(prefixTextNode, wordPrefixLength);
+        } else {
+            var completionTextNode = document.createTextNode(completionText);
+            fullWordRange.insertNode(completionTextNode);           
+
+            if (completions.length > 1)
+                finalSelectionRange.setStart(completionTextNode, wordPrefixLength);
+            else
+                finalSelectionRange.setStart(completionTextNode, completionText.length);
+
+            finalSelectionRange.setEnd(completionTextNode, completionText.length);
+        }
+
+        selection.removeAllRanges();
+        selection.addRange(finalSelectionRange);
+    },
+
+    isCaretInsidePrompt: function()
+    {
+        return this.element.isInsertionCaretInside();
+    },
+
+    isCaretAtEndOfPrompt: function()
+    {
+        var selection = window.getSelection();
+        if (!selection.rangeCount || !selection.isCollapsed)
+            return false;
+
+        var selectionRange = selection.getRangeAt(0);
+        var node = selectionRange.startContainer;
+        if (node !== this.element && !node.isDescendant(this.element))
+            return false;
+
+        if (node.nodeType === Node.TEXT_NODE && selectionRange.startOffset < node.nodeValue.length)
+            return false;
+
+        var foundNextText = false;
+        while (node) {
+            if (node.nodeType === Node.TEXT_NODE && node.nodeValue.length) {
+                if (foundNextText)
+                    return false;
+                foundNextText = true;
+            }
+
+            node = node.traverseNextNode(false, this.element);
+        }
+
+        return true;
+    },
+
+    moveCaretToEndOfPrompt: function()
+    {
+        var selection = window.getSelection();
+        var selectionRange = document.createRange();
+
+        var offset = this.element.childNodes.length;
+        selectionRange.setStart(this.element, offset);
+        selectionRange.setEnd(this.element, offset);
+
+        selection.removeAllRanges();
+        selection.addRange(selectionRange);
+    },
+
+    _tabKeyPressed: function(event)
+    {
+        event.preventDefault();
+        event.stopPropagation();
+
+        this.complete();
+    },
+
+    _upKeyPressed: function(event)
+    {
+        event.preventDefault();
+        event.stopPropagation();
+
+        if (this.historyOffset == this.history.length)
+            return;
+
+        this.clearAutoComplete(true);
+
+        if (this.historyOffset == 0)
+            this.tempSavedCommand = this.text;
+
+        ++this.historyOffset;
+        this.text = this.history[this.history.length - this.historyOffset];
+    },
+
+    _downKeyPressed: function(event)
+    {
+        event.preventDefault();
+        event.stopPropagation();
+
+        if (this.historyOffset == 0)
+            return;
+
+        this.clearAutoComplete(true);
+
+        --this.historyOffset;
+
+        if (this.historyOffset == 0) {
+            this.text = this.tempSavedCommand;
+            delete this.tempSavedCommand;
+            return;
+        }
+
+        this.text = this.history[this.history.length - this.historyOffset];
+    }
+}
diff --git a/resources/Inspector/View.js b/resources/Inspector/View.js
new file mode 100644
index 0000000..632a61a
--- /dev/null
+++ b/resources/Inspector/View.js
@@ -0,0 +1,74 @@
+/*
+ * 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.View = function(element)
+{
+    this.element = element || document.createElement("div");
+    this._visible = false;
+}
+
+WebInspector.View.prototype = {
+    get visible()
+    {
+        return this._visible;
+    },
+
+    set visible(x)
+    {
+        if (this._visible === x)
+            return;
+
+        if (x)
+            this.show();
+        else
+            this.hide();
+    },
+
+    show: function(parentElement)
+    {
+        this._visible = true;
+        if (parentElement && parentElement !== this.element.parentNode) {
+            this.detach();
+            parentElement.appendChild(this.element);
+        }
+        if (!this.element.parentNode && this.attach)
+            this.attach();
+        this.element.addStyleClass("visible");
+    },
+
+    hide: function()
+    {
+        this.element.removeStyleClass("visible");
+        this._visible = false;
+    },
+
+    detach: function()
+    {
+        if (this.element.parentNode)
+            this.element.parentNode.removeChild(this.element);
+    }
+}
+
+WebInspector.View.prototype.__proto__ = WebInspector.Object.prototype;
diff --git a/resources/Inspector/html4-overrides.css b/resources/Inspector/html4-overrides.css
new file mode 100644
index 0000000..ef4f658
--- /dev/null
+++ b/resources/Inspector/html4-overrides.css
@@ -0,0 +1,68 @@
+/* Copyright 2008 Google Inc. All Rights Reserved. */
+/* Author: ojan@google.com (Ojan Vafai) */
+
+/* These styles override the default styling for HTML elements as defined in
+   WebCore/css/html4.css. So far we have used this file exclusively for
+   making our form elements match Firefoxes. If we find other needs for this
+   file we should seriously consider if this is the right place of them. */
+
+input:not([type]), 
+input[type="text"],
+input[type="password"],
+input[type="search"] {
+    margin:0;
+    padding:1px 0;
+}
+
+input[type="checkbox"] {
+    margin:3px 3px 3px 4px;
+}
+
+input[type="radio"] {
+    margin:3px 3px 0 5px;
+}
+
+/* Not sure this is the right color. #EBEBE4 is what Firefox uses.
+   TODO(ojan): Figure out how to support legacy input rendering. 
+   TODO(ojan): Add input[type="file"] once we figure out our file inputs.
+   TODO(ojan): Add input[type="image"] once we figure out our image inputs.
+   TODO(ojan): We probably do the wrong thing if you put an invalid input type.
+               do we care?
+*/
+textarea:disabled,
+input:not([type]):disabled, 
+input[type="text"]:disabled,
+input[type="password"]:disabled,
+input[type="search"]:disabled {
+    background-color: #EBEBE4; 
+}
+
+/* Chrome should render input[type="search"] the same as input with no type.
+   This search thing is an Apple-ism to get mac style search inputs. */
+input[type="search"] {
+    -webkit-appearance: textfield;
+    -webkit-box-sizing: content-box;
+}
+
+input[type="button"], input[type="submit"], input[type="reset"], input[type="file"]::-webkit-file-upload-button, button {
+    /* Matches Firefox */
+    padding: 0 6px;
+    margin: 0;
+}
+
+/* Chrome selects are not rounded. Custom borders for them shouldn't be either. */
+keygen, 
+select, 
+select[size="0"],
+select[size="1"] {
+    -webkit-border-radius: 0;
+    margin: 0;
+}
+
+textarea {
+  font-family: monospace;
+  margin: 1px 0;
+
+  /* Matches IE */
+  padding: 2px;
+}
diff --git a/resources/Inspector/inspector.css b/resources/Inspector/inspector.css
new file mode 100644
index 0000000..c7ca669
--- /dev/null
+++ b/resources/Inspector/inspector.css
@@ -0,0 +1,3004 @@
+/*
+ * Copyright (C) 2006, 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.
+ */
+
+body {
+    cursor: default;
+    height: 100%;
+    width: 100%;
+    overflow: hidden;
+    font-family: Lucida Grande, sans-serif;
+    font-size: 10px;
+    margin: 0;
+    -webkit-text-size-adjust: none;
+    -webkit-user-select: none;
+}
+
+* {
+    -webkit-box-sizing: border-box;
+}
+
+:focus {
+    outline: none;
+}
+
+input[type="search"]:focus, input[type="text"]:focus {
+    outline: auto 5px -webkit-focus-ring-color;
+}
+
+iframe, a img {
+    border: none;
+}
+
+img {
+    -webkit-user-drag: none;
+}
+
+.hidden {
+    display: none !important;
+}
+
+#toolbar {
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    height: 56px;
+    display: -webkit-box;
+    padding: 0 5px;
+    background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(191, 191, 191)), to(rgb(151, 151, 151)));
+    border-bottom: 1px solid rgb(80, 80, 80);
+    -webkit-box-orient: horizontal;
+    -webkit-background-origin: padding;
+    -webkit-background-clip: padding;
+}
+
+body.inactive #toolbar {
+    background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(233, 233, 233)), to(rgb(207, 207, 207)));
+    border-bottom: 1px solid rgb(64%, 64%, 64%);
+}
+
+body.detached.platform-mac-leopard #toolbar {
+    background: transparent !important;
+}
+
+body.attached #toolbar {
+    height: 34px;
+    border-top: 1px solid rgb(100, 100, 100);
+    cursor: row-resize;
+    padding-left: 0;
+}
+
+body.attached.inactive #toolbar {
+    border-top: 1px solid rgb(64%, 64%, 64%);
+}
+
+.toolbar-item {
+    display: -webkit-box;
+    padding: 4px 6px;
+    margin: 0;
+    background-color: transparent;
+    border-style: none;
+    border-color: transparent;
+    -webkit-box-orient: vertical;
+    -webkit-box-align: center;
+    -webkit-box-pack: end;
+}
+
+.toolbar-item.toggleable.toggled-on {
+    border-width: 0 2px 0 2px;
+    padding: 4px 4px;
+    -webkit-border-image: url(Images/toolbarItemSelected.png) 0 2 0 2;
+}
+
+.toolbar-item.flexable-space {
+    -webkit-box-flex: 1;
+    visibility: hidden;
+}
+
+.toolbar-item input {
+    margin-bottom: 8px;
+}
+
+.toolbar-icon {
+    display: inline-block;
+    width: 32px;
+    height: 32px;
+    -webkit-background-size: 100% auto;
+}
+
+body.attached .toolbar-icon {
+    width: 24px;
+    height: 24px;
+    vertical-align: middle;
+}
+
+.toolbar-item:active .toolbar-icon {
+    background-position: 0 32px;
+}
+
+body.attached .toolbar-item:active .toolbar-icon {
+    background-position: 0 24px;
+}
+
+.toolbar-label {
+    font-size: 11px;
+    font-family: Lucida Grande, sans-serif;
+    text-shadow: rgba(255, 255, 255, 0.5) 0 1px 0;
+}
+
+.toolbar-item.toggleable:active .toolbar-label {
+    text-shadow: none;
+}
+
+body.attached .toolbar-label {
+    display: inline-block;
+    vertical-align: middle;
+    margin-left: 3px;
+}
+
+body.attached #search-toolbar-label {
+    display: none;
+}
+
+#search {
+    width: 205px;
+    font-size: 16px;
+    margin-bottom: 5px;
+}
+
+body.attached #search {
+    font-size: 11px;
+    margin-bottom: 8px;
+}
+
+#search-results-matches {
+    font-size: 11px;
+    text-shadow: rgba(255, 255, 255, 0.5) 0 1px 0;
+    margin-bottom: 22px;
+}
+
+body.attached #search-results-matches {
+    margin-bottom: 6px;
+}
+
+.toolbar-item.elements .toolbar-icon {
+    background-image: url(Images/elementsIcon.png);
+}
+
+.toolbar-item.resources .toolbar-icon {
+    background-image: url(Images/resourcesIcon.png);
+}
+
+.toolbar-item.scripts .toolbar-icon {
+    background-image: url(Images/scriptsIcon.png);
+}
+
+.toolbar-item.databases .toolbar-icon {
+    background-image: url(Images/databasesIcon.png);
+}
+
+.toolbar-item.profiles .toolbar-icon {
+    background-image: url(Images/profilesIcon.png);
+}
+
+#close-button {
+    width: 14px;
+    height: 14px;
+    background-image: url(Images/closeButtons.png);
+    background-position: 0 0;
+    background-color: transparent;
+    border: 0 none transparent;
+    margin: 5px 0;
+}
+
+#close-button:hover {
+    background-position: 14px 0;
+}
+
+#close-button:active {
+    background-position: 28px 0;
+}
+
+body.detached .toolbar-item.close {
+    display: none;
+}
+
+#main {
+    position: absolute;
+    z-index: 1;
+    top: 56px;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    overflow: hidden;
+    background-color: white;
+}
+
+body.attached #main {
+    top: 34px;
+}
+
+#main-panels {
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 23px;
+    overflow: hidden;
+}
+
+#main-status-bar {
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    right: 0;
+}
+
+body.console-visible #main-status-bar {
+    height: 24px;
+    background-image: url(Images/statusbarResizerVertical.png), url(Images/statusbarBackground.png);
+    background-repeat: no-repeat, repeat-x;
+    background-position: right center, center;
+    cursor: row-resize;
+}
+
+body.console-visible #main-status-bar * {
+    cursor: default;
+}
+
+body.console-visible #main-panels {
+    bottom: 24px;
+}
+
+.status-bar {
+    background-color: rgb(235, 235, 235);
+    background-image: url(Images/statusbarBackground.png);
+    background-repeat: repeat-x;
+    white-space: nowrap;
+    height: 23px;
+    overflow: hidden;
+    z-index: 12;
+}
+
+.status-bar > div {
+    display: inline-block;
+    vertical-align: top;
+}
+
+.status-bar-item {
+    display: inline-block;
+    height: 24px;
+    padding: 0;
+    margin-left: -1px;
+    margin-right: 0;
+    vertical-align: top;
+    border: 0 transparent none;
+    background-color: transparent;
+}
+
+.status-bar-item:active {
+    position: relative;
+    z-index: 200;
+}
+
+button.status-bar-item {
+    width: 32px;
+    background-image: url(Images/statusbarButtons.png);
+    background-position: 0 0;
+}
+
+button.status-bar-item:active {
+    background-position: 32px 0;
+}
+
+button.status-bar-item:disabled {
+    opacity: 0.5;
+    background-position: 0 0 !important;
+}
+
+select.status-bar-item {
+    min-width: 48px;
+    border-width: 0 17px 0 2px;
+    padding: 0 2px 0 6px;
+    font-weight: bold;
+    color: rgb(48, 48, 48);
+    text-shadow: rgba(255, 255, 255, 0.75) 0 1px 0;
+    -webkit-border-image: url(Images/statusbarMenuButton.png) 0 17 0 2;
+    -webkit-border-radius: 0;
+    -webkit-appearance: none;
+}
+
+select.status-bar-item:active {
+    color: black;
+    -webkit-border-image: url(Images/statusbarMenuButtonSelected.png) 0 17 0 2;
+}
+
+#dock-status-bar-item {
+    background-image: url(Images/dockButtons.png);
+}
+
+body.attached #dock-status-bar-item:active {
+    background-position: 32px 0;
+}
+
+body.detached #dock-status-bar-item {
+    background-position: 0 24px;
+}
+
+body.detached #dock-status-bar-item.toggled-on:active {
+    background-position: 32px 24px;
+}
+
+#console-status-bar-item {
+    background-image: url(Images/consoleButtons.png);
+}
+
+#console-status-bar-item:active {
+    background-position: 32px 0;
+}
+
+#console-status-bar-item.toggled-on {
+    background-position: 0 24px;
+}
+
+#console-status-bar-item.toggled-on:active {
+    background-position: 32px 24px;
+}
+
+#clear-console-status-bar-item {
+    background-image: url(Images/clearConsoleButtons.png);
+}
+
+#clear-console-status-bar-item:active {
+    background-position: 32px 0;
+}
+
+#error-warning-count {
+    position: absolute;
+    right: 16px;
+    top: 0;
+    cursor: pointer;
+    padding: 6px 2px;
+    font-size: 10px;
+    height: 19px;
+}
+
+#error-warning-count:hover {
+    border-bottom: 1px solid rgb(96, 96, 96);
+}
+
+#error-count::before {
+    content: url(Images/errorIcon.png);
+    width: 10px;
+    height: 10px;
+    vertical-align: -1px;
+    margin-right: 2px;
+}
+
+#error-count + #warning-count {
+    margin-left: 6px;
+}
+
+#warning-count::before {
+    content: url(Images/warningIcon.png);
+    width: 10px;
+    height: 10px;
+    vertical-align: -1px;
+    margin-right: 2px;
+}
+
+#console {
+    display: none;
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    height: 200px;
+    background-color: white;
+    background-image: url(Images/statusbarBottomBackground.png);
+    background-repeat: repeat-x;
+    background-position: bottom;
+}
+
+body.console-visible #console {
+    display: block;
+}
+
+#console-status-bar {
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    background: none;
+}
+
+#console-messages {
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 23px;
+    font-size: 10px;
+    font-family: Monaco, Lucida Console, monospace;
+    padding: 2px 0;
+    overflow-y: overlay;
+    -webkit-user-select: text;
+    -webkit-text-size-adjust: auto;
+}
+
+#console-prompt {
+    position: relative;
+    padding: 1px 22px 1px 24px;
+    min-height: 16px; 
+    white-space: pre-wrap;
+    -webkit-user-modify: read-write-plaintext-only;
+}
+
+#console-prompt::before {
+    background-image: url(Images/userInputIcon.png);
+}
+
+.console-message, .console-user-command {
+    position: relative;
+    border-bottom: 1px solid rgb(240, 240, 240);
+    padding: 1px 22px 1px 24px;
+    min-height: 16px;
+}
+
+.console-message::before, .console-user-command::before, #console-prompt::before, .console-group-title-level::before {
+    position: absolute;
+    display: block;
+    content: "";
+    left: 7px;
+    top: 0.8em;
+    width: 10px;
+    height: 10px;
+    margin-top: -5px;
+    -webkit-user-select: none;
+}
+
+.console-message .bubble {
+    display: inline-block;
+    height: 14px;
+    background-color: rgb(128, 151, 189);
+    vertical-align: middle;
+    white-space: nowrap;
+    padding: 1px 4px;
+    margin-top: -2px;
+    margin-right: 4px;
+    text-align: left;
+    font-size: 11px;
+    font-family: Helvetia, Arial, sans-serif;
+    font-weight: bold;
+    text-shadow: none;
+    color: white;
+    -webkit-border-radius: 7px;
+}
+
+.console-message-text {
+    white-space: pre-wrap;
+}
+
+.repeated-message {
+    padding-left: 6px;
+}
+
+.repeated-message.console-error-level::before, .repeated-message.console-warning-level:before {
+    visibility: hidden;
+}
+
+.console-group .console-group > .console-group-messages {
+    margin-left: 16px;
+}
+
+.console-group-title-level {
+    font-weight: bold;
+}
+
+.console-group-title-level::before {
+    background-image: url(Images/disclosureTriangleSmallDown.png);
+    top: 0.6em;
+    width: 11px;
+    height: 12px;
+}
+
+.console-group.collapsed .console-group-title-level::before {
+    background-image: url(Images/disclosureTriangleSmallRight.png);
+}
+
+.console-group.collapsed > .console-group-messages {
+    display: none;
+}
+
+.console-error-level .console-message-text {
+    color: red;
+}
+
+.console-error-level::before {
+    background-image: url(Images/errorIcon.png);
+}
+
+.console-warning-level::before {
+    background-image: url(Images/warningIcon.png);
+}
+
+.console-user-command .console-message {
+    margin-left: -24px;
+    padding-right: 0;
+    border-bottom: none;
+}
+
+.console-user-command::before {
+    background-image: url(Images/userInputPreviousIcon.png);
+}
+
+.console-user-command > .console-message-text {
+    color: rgb(0, 128, 255);
+}
+
+.console-message-url {
+    color: rgb(33%, 33%, 33%) !important;
+    cursor: pointer;
+    float: right;
+}
+
+.console-message-url:hover {
+    color: rgb(15%, 15%, 15%);
+}
+
+.console-message-url:hover::after {
+    opacity: 1;
+}
+
+.console-group-messages .section {
+    margin: 0;
+}
+
+.console-group-messages .section .header {
+    padding: 0 8px 0 0;
+    background-image: none;
+    border: none;
+    min-height: 16px;
+}
+
+.console-group-messages .section .header::before {
+    position: absolute;
+    top: 1px;
+    left: 12px;
+    width: 8px;
+    height: 8px;
+    content: url(Images/treeRightTriangleBlack.png);
+}
+
+.console-group-messages .section.expanded .header::before {
+    content: url(Images/treeDownTriangleBlack.png);
+}
+
+.console-group-messages .section .header .title {
+    color: black;
+}
+
+.console-group-messages .outline-disclosure, .console-group-messages .outline-disclosure ol {
+    font-size: inherit;
+    line-height: 1em;
+}
+
+.console-group-messages .outline-disclosure li {
+    padding-top: 2px;
+    padding-bottom: 2px;
+}
+
+.console-group-messages .outline-disclosure li .selection {
+    z-index: 0;
+    margin-top: -1px;
+}
+
+.console-formatted-object .section, .console-formatted-node .section {
+    position: static;
+}
+
+.auto-complete-text {
+    color: rgb(128, 128, 128);
+    -webkit-user-select: none;
+    -webkit-user-modify: read-only;
+}
+
+.inspectible-node:hover {
+    background-color: rgba(56, 121, 217, 0.1);
+    -webkit-border-radius: 5px;
+    padding: 0 5px 1px;
+    margin: 0 -5px -1px;
+}
+
+.panel {
+    display: none;
+    overflow: hidden;
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+}
+
+.panel.visible {
+    display: block;
+}
+
+.resource-view {
+    display: none;
+    overflow: hidden;
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    overflow: hidden;
+}
+
+.resource-view.visible {
+    display: block;
+}
+
+.resource-view.headers-visible {
+    overflow-y: auto;
+    overflow-x: hidden;
+}
+
+.resource-view-headers {
+    display: none;
+    padding: 6px;
+    border-bottom: 1px solid rgb(64%, 64%, 64%);
+    background-color: white;
+    -webkit-user-select: text;
+}
+
+.resource-view-headers .outline-disclosure .parent {
+    -webkit-user-select: none;
+    font-weight: bold;
+}
+
+.resource-view.headers-visible .resource-view-headers {
+    display: block;
+}
+
+.resource-view-headers .outline-disclosure .children li {
+    white-space: nowrap;
+}
+
+.resource-view-headers .outline-disclosure li.expanded .header-count {
+    display: none;
+}
+
+.resource-view-headers .outline-disclosure .header-name {
+    color: rgb(33%, 33%, 33%);
+    display: inline-block;
+    width: 105px;
+    text-align: right;
+    margin-right: 0.5em;
+    font-weight: bold;
+    vertical-align: top;
+    overflow: hidden;
+    text-overflow: ellipsis;
+}
+
+.resource-view-headers .outline-disclosure .header-value {
+    display: inline-block;
+    white-space: normal;
+    word-break: break-word;
+    vertical-align: top;
+    margin-right: 100px;
+}
+
+.resource-view .resource-view-content {
+    position: absolute;
+    top: 0;
+    right: 0;
+    left: 0;
+    bottom: 0;
+}
+
+.resource-view.headers-visible .resource-view-content {
+    position: relative;
+    top: auto;
+    right: auto;
+    left: auto;
+    bottom: auto;
+}
+
+.resource-view.headers-visible .source-view-frame {
+    height: auto;
+    vertical-align: top;
+}
+
+.webkit-line-gutter-backdrop {
+    /* Keep this in sync with view-source.css (.webkit-line-gutter-backdrop) */
+    width: 31px;
+    background-color: rgb(240, 240, 240);
+    border-right: 1px solid rgb(187, 187, 187);
+    position: absolute;
+    z-index: -1;
+    left: 0;
+    top: 0;
+    height: 100%
+}
+
+.resource-view.font .resource-view-content {
+    font-size: 60px;
+    white-space: pre-wrap;
+    word-wrap: break-word;
+    text-align: center;
+    padding: 15px;
+}
+
+.resource-view.image .resource-view-content > .image {
+    padding: 20px 20px 10px 20px;
+    text-align: center;
+}
+
+.resource-view.image .resource-view-content > .info {
+    padding-bottom: 10px;
+    font-size: 11px;
+    -webkit-user-select: text;
+}
+
+.resource-view.image img {
+    max-width: 100%;
+    max-height: 1000px;
+    background-image: url(Images/checker.png);
+    -webkit-box-shadow: 0px 5px 10px rgba(0, 0, 0, 0.5);
+    -webkit-user-select: text;
+    -webkit-user-drag: auto;
+}
+
+.resource-view.image .title {
+    text-align: center;
+    font-size: 13px;
+}
+
+.resource-view.image .infoList {
+    margin: 0;
+}
+
+.resource-view.image .infoList dt {
+    font-weight: bold;
+    display: inline-block;
+    width: 50%;
+    text-align: right;
+    color: rgb(76, 76, 76);
+}
+
+.resource-view.image .infoList dd {
+    display: inline-block;
+    padding-left: 8px;
+    width: 50%;
+    text-align: left;
+    margin: 0;
+}
+
+.resource-view.image .infoList dd::after {
+    white-space: pre;
+    content: "\A";
+}
+
+#elements-content {
+    display: block;
+    overflow: auto;
+    padding: 0;
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 225px;
+    bottom: 0;
+}
+
+#elements-sidebar {
+    position: absolute;
+    top: 0;
+    right: 0;
+    bottom: 0;
+    width: 225px;
+    background-color: rgb(245, 245, 245);
+    border-left: 1px solid rgb(64%, 64%, 64%);
+    cursor: default;
+    overflow: auto;
+}
+
+.crumbs {
+    display: inline-block;
+    font-size: 11px;
+    line-height: 19px;
+    text-shadow: rgba(255, 255, 255, 0.75) 0 1px 0;
+    color: rgb(20, 20, 20);
+    margin-left: -1px;
+    padding-right: 12px;
+}
+
+.crumbs .crumb {
+    height: 24px;
+    border-width: 0 12px 0 2px;
+    -webkit-border-image: url(Images/segment.png) 0 12 0 2;
+    margin-right: -12px;
+    padding-left: 18px;
+    padding-right: 2px;
+    white-space: nowrap;
+    line-height: 23px;
+    float: right;
+}
+
+.crumbs .crumb.collapsed > * {
+    display: none;
+}
+
+.crumbs .crumb.collapsed::before {
+    content: "\2026";
+    font-weight: bold;
+}
+
+.crumbs .crumb.compact .extra {
+    display: none;
+}
+
+.crumbs .crumb.dimmed {
+    color: rgba(0, 0, 0, 0.45);
+}
+
+.crumbs .crumb.start {
+    padding-left: 7px;
+}
+
+.crumbs .crumb.end {
+    border-width: 0 2px 0 2px;
+    padding-right: 6px;
+    -webkit-border-image: url(Images/segmentEnd.png) 0 2 0 2;
+}
+
+.crumbs .crumb.selected {
+    -webkit-border-image: url(Images/segmentSelected.png) 0 12 0 2;
+    color: black;
+    text-shadow: rgba(255, 255, 255, 0.5) 0 1px 0;
+}
+
+.crumbs .crumb.selected:hover {
+    -webkit-border-image: url(Images/segmentSelected.png) 0 12 0 2;
+}
+
+.crumbs .crumb.selected.end, .crumbs .crumb.selected.end:hover {
+    -webkit-border-image: url(Images/segmentSelectedEnd.png) 0 2 0 2;
+}
+
+.crumbs .crumb:hover {
+    -webkit-border-image: url(Images/segmentHover.png) 0 12 0 2;
+    color: black;
+}
+
+.crumbs .crumb.dimmed:hover {
+    -webkit-border-image: url(Images/segmentHover.png) 0 12 0 2;
+    color: rgba(0, 0, 0, 0.75);
+}
+
+.crumbs .crumb.end:hover {
+    -webkit-border-image: url(Images/segmentHoverEnd.png) 0 2 0 2;
+}
+
+.outline-disclosure li.hovered:not(.selected) .selection {
+    display: block;
+    left: 3px;
+    right: 3px;
+    background-color: rgba(56, 121, 217, 0.1);
+    -webkit-border-radius: 5px;
+}
+
+.outline-disclosure li.highlighted .highlight {
+    background-color: rgb(255, 230, 179);
+    -webkit-border-radius: 4px;
+    padding-bottom: 2px;
+    margin-bottom: -2px;
+}
+
+.outline-disclosure li.selected.highlighted .highlight {
+    background-color: transparent;
+    padding-bottom: 0;
+    margin-bottom: 0;
+}
+
+.outline-disclosure li .selection {
+    display: none;
+    position: absolute;
+    left: 0;
+    right: 0;
+    height: 15px;
+    z-index: -1;
+}
+
+.outline-disclosure li.selected .selection {
+    display: block;
+    background-color: rgb(212, 212, 212);
+}
+
+:focus .outline-disclosure li.selected .selection {
+    background-color: rgb(56, 121, 217);
+}
+
+.outline-disclosure > ol {
+    position: relative;
+    padding: 2px 6px !important;
+    margin: 0;
+    color: black;
+    cursor: default;
+    min-width: 100%;
+}
+
+.outline-disclosure, .outline-disclosure ol {
+    list-style-type: none;
+    font-size: 11px;
+    -webkit-padding-start: 12px;
+    margin: 0;
+}
+
+.outline-disclosure li {
+    padding: 0 0 2px 14px;
+    margin-top: 1px;
+    margin-bottom: 1px;
+    word-wrap: break-word;
+    text-indent: -2px
+}
+
+:focus .outline-disclosure li.selected {
+    color: white;
+}
+
+:focus .outline-disclosure li.selected * {
+    color: inherit;
+}
+
+.outline-disclosure li.parent {
+    text-indent: -12px
+}
+
+.outline-disclosure li .webkit-html-tag.close {
+    margin-left: -12px;
+}
+
+.outline-disclosure li.parent::before {
+    content: url(Images/treeRightTriangleBlack.png);
+    float: left;
+    width: 8px;
+    height: 8px;
+    margin-top: 1px;
+    padding-right: 2px;
+}
+
+.outline-disclosure li.parent::before {
+    content: url(Images/treeRightTriangleBlack.png);
+}
+
+:focus .outline-disclosure li.parent.selected::before {
+    content: url(Images/treeRightTriangleWhite.png);
+}
+
+.outline-disclosure li.parent.expanded::before {
+    content: url(Images/treeDownTriangleBlack.png);
+}
+
+:focus .outline-disclosure li.parent.expanded.selected::before {
+    content: url(Images/treeDownTriangleWhite.png);
+}
+
+.outline-disclosure ol.children {
+    display: none;
+}
+
+.outline-disclosure ol.children.expanded {
+    display: block;
+}
+
+.webkit-html-comment {
+    /* Keep this in sync with view-source.css (.webkit-html-comment) */
+    color: rgb(35, 110, 37);
+}
+
+.webkit-html-tag {
+    /* Keep this in sync with view-source.css (.webkit-html-tag) */
+    color: rgb(136, 18, 128);
+}
+
+.webkit-html-doctype {
+    /* Keep this in sync with view-source.css (.webkit-html-doctype) */
+    color: rgb(192, 192, 192);
+}
+
+.webkit-html-attribute-name {
+    /* Keep this in sync with view-source.css (.webkit-html-attribute-name) */
+    color: rgb(153, 69, 0);
+}
+
+.webkit-html-attribute-value {
+    /* Keep this in sync with view-source.css (.webkit-html-attribute-value) */
+    color: rgb(26, 26, 166);
+}
+
+.webkit-html-external-link, .webkit-html-resource-link {
+    /* Keep this in sync with view-source.css (.webkit-html-external-link, .webkit-html-resource-link) */
+    color: #00e;
+}
+
+.webkit-html-external-link {
+    /* Keep this in sync with view-source.css (.webkit-html-external-link) */
+    text-decoration: none;
+}
+
+.webkit-html-external-link:hover {
+    /* Keep this in sync with view-source.css (.webkit-html-external-link:hover) */
+    text-decoration: underline;
+}
+
+.placard {
+    position: relative;
+    margin-top: 1px;
+    padding: 3px 8px 4px 18px;
+    min-height: 18px;
+    white-space: nowrap;
+}
+
+.placard:nth-of-type(2n) {
+    background-color: rgb(234, 243, 255);
+}
+
+.placard.selected {
+    border-top: 1px solid rgb(145, 160, 192);
+    background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(162, 177, 207)), to(rgb(120, 138, 177)));
+    -webkit-background-origin: padding;
+    -webkit-background-clip: padding;
+}
+
+:focus .placard.selected {
+    border-top: 1px solid rgb(68, 128, 200);
+    background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(92, 147, 213)), to(rgb(21, 83, 170)));
+}
+
+body.inactive .placard.selected {
+    border-top: 1px solid rgb(151, 151, 151);
+    background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(180, 180, 180)), to(rgb(138, 138, 138)));
+}
+
+.placard .title {
+    color: black;
+    font-weight: normal;
+    word-wrap: break-word;
+    white-space: normal;
+}
+
+.placard.selected .title {
+    color: white;
+    font-weight: bold;
+}
+
+.placard .subtitle {
+    float: right;
+    font-size: 10px;
+    margin-left: 5px;
+    max-width: 55%;
+    color: rgba(0, 0, 0, 0.7);
+    text-overflow: ellipsis;
+    overflow: hidden;
+}
+
+.placard.selected .subtitle {
+    color: rgba(255, 255, 255, 0.7);
+}
+
+.placard .subtitle a {
+    color: inherit;
+}
+
+.section {
+    position: relative;
+    margin-top: 1px;
+}
+
+.section:nth-last-of-type(1) {
+    margin-bottom: 1px;
+}
+
+.section .header {
+    padding: 2px 8px 4px 18px;
+    border-top: 1px solid rgb(145, 160, 192);
+    background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(162, 177, 207)), to(rgb(120, 138, 177)));
+    min-height: 18px;
+    white-space: nowrap;
+    -webkit-background-origin: padding;
+    -webkit-background-clip: padding;
+}
+
+.section .header::before {
+    position: absolute;
+    top: 4px;
+    left: 7px;
+    width: 8px;
+    height: 8px;
+    content: url(Images/treeRightTriangleWhite.png);
+}
+
+.section.expanded .header::before {
+    content: url(Images/treeDownTriangleWhite.png);
+}
+
+.section .header .title {
+    color: white;
+    font-weight: bold;
+    word-wrap: break-word;
+    white-space: normal;
+}
+
+.section .header label {
+    display: none;
+}
+
+.section.expanded .header label {
+    display: inline;
+}
+
+.section .header input[type=checkbox] {
+    height: 10px;
+    width: 10px;
+    margin-left: 0;
+    margin-top: 0;
+    margin-bottom: 0;
+    vertical-align: 2px;
+}
+
+.section .header .subtitle {
+    float: right;
+    font-size: 10px;
+    margin-left: 5px;
+    max-width: 55%;
+    color: rgba(255, 255, 255, 0.7);
+    text-overflow: ellipsis;
+    overflow: hidden;
+}
+
+.section .header .subtitle a {
+    color: inherit;
+}
+
+.section .properties {
+    display: none;
+    margin: 0;
+    padding: 2px 6px 3px;
+    list-style: none;
+    background-color: white;
+}
+
+.section.expanded .properties {
+    display: block;
+}
+
+.section .properties li {
+    margin-left: 12px;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    overflow: hidden;
+    -webkit-user-select: text;
+    cursor: auto;
+}
+
+.section .properties li.parent {
+    margin-left: 1px;
+}
+
+.section .properties ol {
+    display: none;
+    margin: 0;
+    -webkit-padding-start: 12px;
+    list-style: none;
+}
+
+.section .properties ol.expanded {
+    display: block;
+}
+
+.section .properties li.parent::before {
+    content: url(Images/treeRightTriangleBlack.png);
+    opacity: 0.75;
+    float: left;
+    width: 8px;
+    height: 8px;
+    margin-top: 0;
+    padding-right: 3px;
+    -webkit-user-select: none;
+    cursor: default;
+}
+
+.section .properties li.parent.expanded::before {
+    content: url(Images/treeDownTriangleBlack.png);
+    margin-top: 1px;
+}
+
+.section .properties li .info {
+    padding-top: 4px;
+    padding-bottom: 3px;
+}
+
+.editing {
+    -webkit-user-select: text;
+    -webkit-box-shadow: rgba(0, 0, 0, .5) 3px 3px 4px;
+    outline: 1px solid rgb(66%, 66%, 66%) !important;
+    background-color: white;
+    -webkit-user-modify: read-write-plaintext-only;
+    text-overflow: clip;
+    padding-left: 2px;
+    margin-left: -2px;
+    padding-right: 2px;
+    margin-right: -2px;
+    margin-bottom: -1px;
+    padding-bottom: 1px;
+    opacity: 1.0 !important;
+}
+
+.editing, .editing * {
+    color: black !important;
+    text-decoration: none !important;
+}
+
+.section .properties li.editing {
+    margin-left: 10px;
+    text-overflow: clip;
+}
+
+li.editing .swatch, li.editing .enabled-button {
+    display: none !important;
+}
+
+.section .properties li.editing-sub-part {
+    padding: 3px 6px 8px 18px;
+    margin: -3px -6px -8px -6px;
+    text-overflow: clip;
+}
+
+.section .properties .overloaded, .section .properties .disabled {
+    text-decoration: line-through;
+}
+
+.section.computed-style .properties .disabled {
+    text-decoration: none;
+    opacity: 0.5;
+}
+
+.section .properties .implicit, .section .properties .inherited {
+    opacity: 0.5;
+}
+
+.section:not(.show-inherited) .properties .inherited {
+    display: none;
+}
+
+.section .properties .enabled-button {
+    display: none;
+    float: right;
+    font-size: 10px;
+    margin: 0 0 0 4px;
+    vertical-align: top;
+    position: relative;
+    z-index: 1;
+}
+
+.section:hover .properties .enabled-button {
+    display: block;
+}
+
+.section .properties .name {
+    color: rgb(136, 19, 145);
+}
+
+.section .properties .value.dimmed {
+    color: rgb(100, 100, 100);
+}
+
+.section .properties .number {
+    color: blue;
+}
+
+.section .properties .priority {
+    color: rgb(128, 0, 0);
+}
+
+.section .properties .keyword {
+    color: rgb(136, 19, 79);
+}
+
+.section .properties .color {
+    color: rgb(118, 15, 21);
+}
+
+.swatch {
+    display: inline-block;
+    vertical-align: baseline;
+    margin-left: 4px;
+    margin-bottom: -1px;
+    width: 1em;
+    height: 1em;
+    border: 1px solid rgb(180, 180, 180);
+}
+
+.pane:not(.expanded) + .pane, .pane:first-of-type {
+    margin-top: -1px;
+}
+
+.pane > .title {
+    background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(243, 243, 243)), color-stop(0.05, rgb(243, 243, 243)), color-stop(0.05, rgb(230, 230, 230)), to(rgb(209, 209, 209)));
+    height: 20px;
+    padding: 0 5px;
+    border-top: 1px solid rgb(189, 189, 189);
+    border-bottom: 1px solid rgb(189, 189, 189);
+    font-weight: bold;
+    font-size: 12px;
+    line-height: 18px;
+    color: rgb(110, 110, 110);
+    text-shadow: white 0 1px 0;
+    -webkit-background-origin: padding;
+    -webkit-background-clip: padding;
+}
+
+.pane > .title:active {
+    background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(231, 231, 231)), color-stop(0.05, rgb(231, 231, 231)), color-stop(0.05, rgb(207, 207, 207)), to(rgb(186, 186, 186)));
+    border-top: 1px solid rgb(178, 178, 178);
+    border-bottom: 1px solid rgb(178, 178, 178);
+}
+
+.pane > .title::before {
+    content: url(Images/disclosureTriangleSmallRightBlack.png);
+    float: left;
+    width: 11px;
+    height: 12px;
+    margin-right: 2px;
+    margin-top: 1px;
+}
+
+.pane.expanded > .title::before {
+    content: url(Images/disclosureTriangleSmallDownBlack.png);
+}
+
+.pane > .body {
+    position: relative;
+    display: none;
+    background-color: white;
+    overflow-y: auto;
+    overflow-x: hidden;
+}
+
+.pane > .body .info {
+    text-align: center;
+    font-style: italic;
+    font-size: 10px;
+    padding: 6px;
+    color: gray;
+}
+
+.pane.expanded > .body, .pane.expanded > .growbar {
+    display: block;
+}
+
+.pane.expanded:nth-last-of-type(1) {
+    border-bottom: 1px solid rgb(189, 189, 189);
+}
+
+.pane > .growbar {
+    display: none;
+    background-image: url(Images/paneGrowHandleLine.png), url(Images/paneBottomGrow.png);
+    background-repeat: no-repeat, repeat-x;
+    background-position: center center, bottom;
+    height: 5px;
+}
+
+.metrics {
+    padding: 8px;
+    font-size: 10px;
+    text-align: center;
+    white-space: nowrap;
+}
+
+.metrics .label {
+    position: absolute;
+    margin-top: -10px;
+    font-size: 9px;
+    color: grey;
+    background-color: white;
+    margin-left: 3px;
+    padding-left: 2px;
+    padding-right: 2px;
+}
+
+.metrics .position {
+    border: 1px rgb(66%, 66%, 66%) dotted;
+    display: inline-block;
+    text-align: center;
+    padding: 3px;
+    margin: 3px;
+}
+
+.metrics .margin {
+    border: 1px dashed;
+    display: inline-block;
+    text-align: center;
+    vertical-align: middle;
+    padding: 3px;
+    margin: 3px;
+}
+
+.metrics .border {
+    border: 1px black solid;
+    display: inline-block;
+    text-align: center;
+    vertical-align: middle;
+    padding: 3px;
+    margin: 3px;
+}
+
+.metrics .padding {
+    border: 1px grey dashed;
+    display: inline-block;
+    text-align: center;
+    vertical-align: middle;
+    padding: 3px;
+    margin: 3px;
+}
+
+.metrics .content {
+    position: static;
+    border: 1px grey solid;
+    display: inline-block;
+    text-align: center;
+    vertical-align: middle;
+    padding: 3px;
+    margin: 3px;
+    min-width: 80px;
+    text-align: center;
+    overflow: visible;
+}
+
+.metrics .content span {
+    display: inline-block;
+}
+
+.metrics .editing {
+    position: relative;
+    z-index: 100;
+}
+
+.metrics .left {
+    display: inline-block;
+    vertical-align: middle;
+}
+
+.metrics .right {
+    display: inline-block;
+    vertical-align: middle;
+}
+
+.metrics .top {
+    display: inline-block;
+}
+
+.metrics .bottom {
+    display: inline-block;
+}
+
+.sidebar {
+    position: absolute;
+    top: 0;
+    left: 0;
+    bottom: 0;
+    width: 200px;
+    overflow-y: auto;
+    overflow-x: hidden;
+    background-color: rgb(214, 221, 229);
+    border-right: 1px solid rgb(64%, 64%, 64%);
+}
+
+body.inactive .sidebar {
+    background-color: rgb(232, 232, 232);
+}
+
+.database-sidebar-tree-item .icon {
+    content: url(Images/database.png);
+}
+
+.database-table-sidebar-tree-item .icon {
+    content: url(Images/databaseTable.png);
+}
+
+.domstorage-sidebar-tree-item .icon {
+    content: url(Images/domStorage.png);
+}
+
+#storage-views {
+    position: absolute;
+    top: 0;
+    right: 0;
+    left: 200px;
+    bottom: 0;
+}
+
+.storage-view {
+    display: none;
+    overflow: hidden;
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+}
+
+.storage-view.visible {
+    display: block;
+}
+
+.storage-view.table {
+    overflow: hidden;
+}
+
+.storage-view.table .data-grid {
+    border: none;
+    height: 100%;
+}
+
+.storage-view.table .storage-table-empty, .storage-view.table .storage-table-error {
+    position: absolute;
+    top: 0;
+    bottom: 25%;
+    left: 0;
+    right: 0;
+    font-size: 24px;
+    color: rgb(75%, 75%, 75%);
+    margin-top: auto;
+    margin-bottom: auto;
+    height: 50px;
+    line-height: 26px;
+    text-align: center;
+    font-weight: bold;
+    padding: 10px;
+    white-space: pre-wrap;
+}
+
+.storage-view.table .storage-table-error {
+    color: rgb(66%, 33%, 33%);
+}
+
+.data-grid {
+    position: relative;
+    border: 1px solid #aaa;
+}
+
+.data-grid .highlight {
+    background-color: rgb(255, 230, 179);
+}
+
+.data-grid tr.selected .highlight {
+    background-color: transparent;
+}
+
+.data-grid table {
+    table-layout: fixed;
+    border-spacing: 0;
+    border-collapse: collapse;
+    width: 100%;
+    font-size: 10px;
+    font-family: Lucida Grande, sans-serif;
+}
+
+.data-grid .data-container {
+    position: absolute;
+    top: 16px;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    padding-right: 14px;
+    overflow-x: hidden;
+    overflow-y: overlay;
+    background-image: -webkit-gradient(linear, left top, left bottom, from(white), color-stop(0.5, white), color-stop(0.5, rgb(234, 243, 255)), to(rgb(234, 243, 255)));
+    -webkit-background-size: 1px 32px;
+}
+
+.data-grid.inline .data-container {
+    position: static;
+}
+
+.data-grid th {
+    text-align: left;
+    background-image: url(Images/glossyHeader.png);
+    background-repeat: repeat-x;
+    border-right: 1px solid rgb(179, 179, 179);
+    border-bottom: 1px solid rgb(179, 179, 179);
+    height: 15px;
+    font-weight: normal;
+    vertical-align: middle;
+    padding: 0 4px;
+    white-space: nowrap;
+}
+
+.data-grid th.corner {
+    width: 15px;
+    border-right: 0 none transparent;
+}
+
+.data-grid tr.filler {
+    display: table-row !important;
+    height: auto !important;
+}
+
+.data-grid tr.filler td {
+    height: auto !important;
+    padding: 0 !important;
+}
+
+.data-grid table.data {
+    position: absolute;
+    left: 0;
+    top: 0;
+    right: 16px;
+    bottom: 0;
+    height: 100%;
+    border-top: 0 none transparent;
+    background-image: -webkit-gradient(linear, left top, left bottom, from(white), color-stop(0.5, white), color-stop(0.5, rgb(234, 243, 255)), to(rgb(234, 243, 255)));
+    -webkit-background-size: 1px 32px;
+}
+
+.data-grid.inline table.data {
+    position: static;
+}
+
+.data-grid table.data tr {
+    display: none;
+}
+
+.data-grid table.data tr.revealed {
+    display: table-row;
+}
+
+.data-grid td {
+    vertical-align: top;
+    height: 12px;
+    padding: 2px 4px;
+    white-space: nowrap;
+    border-right: 1px solid #aaa;
+    -webkit-user-select: text;
+}
+
+.data-grid td > div, .data-grid th > div {
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    overflow: hidden;
+}
+
+.data-grid th.sortable div {
+    position: relative;
+}
+
+.data-grid th.sortable:active {
+    background-image: url(Images/glossyHeaderPressed.png);
+}
+
+.data-grid th.sort-ascending, .data-grid th.sort-descending {
+    border-right: 1px solid rgb(107, 140, 196);
+    border-bottom: 1px solid rgb(107, 140, 196);
+    background-image: url(Images/glossyHeaderSelected.png);
+    background-repeat: repeat-x;
+}
+
+.data-grid th.sortable.sort-ascending:active, .data-grid th.sortable.sort-descending:active {
+    background-image: url(Images/glossyHeaderSelectedPressed.png);
+}
+
+.data-grid th.sort-ascending div::after {
+    position: absolute;
+    top: 0;
+    right: 0;
+    width: 8px;
+    height: 8px;
+    content: url(Images/treeUpTriangleBlack.png);
+}
+
+.data-grid th.sort-descending div::after {
+    position: absolute;
+    top: 0;
+    right: 0;
+    margin-top: 1px;
+    width: 8px;
+    height: 8px;
+    content: url(Images/treeDownTriangleBlack.png);
+}
+
+body.inactive .data-grid th.sort-ascending, body.inactive .data-grid th.sort-descending {
+    background-image: url(Images/glossyHeader.png);
+    border-right: 1px solid rgb(179, 179, 179);
+    border-bottom: 1px solid rgb(179, 179, 179);
+}
+
+.data-grid tr.parent td.disclosure::before {
+    float: left;
+    content: url(Images/treeRightTriangleBlack.png);
+    width: 8px;
+    height: 8px;
+    margin-right: 2px;
+    -webkit-user-select: none;
+}
+
+.data-grid tr.expanded td.disclosure::before {
+    content: url(Images/treeDownTriangleBlack.png);
+    width: 8px;
+    height: 8px;
+    margin-top: 1px;
+}
+
+.data-grid tr.selected {
+    background-color: rgb(212, 212, 212);
+    color: inherit;
+}
+
+.data-grid:focus tr.selected {
+    background-color: rgb(56, 121, 217);
+    color: white;
+}
+
+.data-grid:focus tr.parent.selected td.disclosure::before {
+    content: url(Images/treeRightTriangleWhite.png);
+}
+
+.data-grid:focus tr.expanded.selected td.disclosure::before {
+    content: url(Images/treeDownTriangleWhite.png);
+}
+
+.data-grid tr:not(.parent) td.disclosure {
+    text-indent: 10px;
+}
+
+.storage-view.query {
+    font-size: 10px;
+    font-family: Monaco, Lucida Console, monospace;
+    padding: 2px 0;
+    overflow-y: overlay;
+    overflow-x: hidden;
+    -webkit-text-size-adjust: auto;
+}
+
+.database-query-prompt {
+    position: relative;
+    padding: 1px 22px 1px 24px;
+    min-height: 16px; 
+    white-space: pre-wrap;
+    -webkit-user-modify: read-write-plaintext-only;
+    -webkit-user-select: text;
+}
+
+.database-user-query::before, .database-query-prompt::before, .database-query-result::before {
+    position: absolute;
+    display: block;
+    content: "";
+    left: 7px;
+    top: 0.8em;
+    width: 10px;
+    height: 10px;
+    margin-top: -5px;
+    -webkit-user-select: none;
+}
+
+.database-query-prompt::before {
+    background-image: url(Images/userInputIcon.png);
+}
+
+.database-user-query {
+    position: relative;
+    border-bottom: 1px solid rgb(245, 245, 245);
+    padding: 1px 22px 1px 24px;
+    min-height: 16px; 
+}
+
+.database-user-query::before {
+    background-image: url(Images/userInputPreviousIcon.png);
+}
+
+.database-query-text {
+    color: rgb(0, 128, 255);
+    -webkit-user-select: text;
+}
+
+.database-query-result {
+    position: relative;
+    padding: 1px 22px 1px 24px;
+    min-height: 16px;
+    margin-left: -24px;
+    padding-right: 0;
+}
+
+.database-query-result.error {
+    color: red;
+    -webkit-user-select: text;
+}
+
+.database-query-result.error::before {
+    background-image: url(Images/errorIcon.png);
+}
+
+.panel-enabler-view {
+    z-index: 1000;
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background-color: white;
+    font-size: 13px;
+    text-align: center;
+    overflow-x: hidden;
+    overflow-y: overlay;
+    display: none;
+}
+
+.panel-enabler-view.visible {
+    display: block;
+}
+
+.panel-enabler-view .panel-enabler-view-content {
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    max-height: 390px;
+    margin: auto;
+    white-space: nowrap;
+}
+
+.panel-enabler-view h1 {
+    color: rgb(110, 116, 128);
+    font-size: 16px;
+    line-height: 20px;
+    font-weight: normal;
+    margin-top: 0;
+}
+
+.panel-enabler-disclaimer {
+    font-size: 10px;
+    color: rgb(110, 116, 128);
+    margin-bottom: 12px;
+}
+
+.panel-enabler-disclaimer:empty {
+    display: none;
+}
+
+.panel-enabler-view img {
+    height: 100%;
+    min-height: 200px;
+    max-width: 100%;
+    top: 0;
+    bottom: 0;
+    padding: 20px 0 20px 20px;
+    margin: auto;
+    vertical-align: middle;
+}
+
+.panel-enabler-view img.hidden {
+    display: initial !important;
+    width: 0;
+}
+
+.panel-enabler-view form {
+    display: inline-block;
+    vertical-align: middle;
+    width: 330px;
+    margin: 0;
+    padding: 15px;
+    white-space: normal;
+}
+
+.panel-enabler-view label {
+    position: relative;
+    display: block;
+    text-align: left;
+    margin-left: 50px;
+    margin-bottom: 6px;
+    line-height: 18px;
+    word-break: break-word;
+}
+
+.panel-enabler-view button {
+    font-size: 13px;
+    margin: 6px 0 0 0;
+    padding: 3px 20px;
+    color: rgb(6, 6, 6);
+    height: 24px;
+    background-color: transparent;
+    border: 1px solid rgb(165, 165, 165);
+    background-color: rgb(237, 237, 237);
+    background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(252, 252, 252)), to(rgb(223, 223, 223)));
+    -webkit-border-radius: 12px;
+    -webkit-appearance: none;
+}
+
+.panel-enabler-view button:active {
+    background-color: rgb(215, 215, 215);
+    background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(194, 194, 194)), to(rgb(239, 239, 239)));
+}
+
+body.inactive .panel-enabler-view button, .panel-enabler-view button:disabled {
+    color: rgb(130, 130, 130);
+    border-color: rgb(212, 212, 212);
+    background-color: rgb(239, 239, 239);
+    background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(250, 250, 250)), to(rgb(235, 235, 235)));
+}
+
+.panel-enabler-view.scripts img {
+    content: url(Images/scriptsSilhouette.png);
+}
+
+.panel-enabler-view.profiles img {
+    content: url(Images/profilesSilhouette.png);
+}
+
+button.enable-toggle-status-bar-item {
+    background-image: url(Images/enableButtons.png);
+}
+
+button.enable-toggle-status-bar-item:active {
+    background-position: 32px 0;
+}
+
+button.enable-toggle-status-bar-item.toggled-on {
+    background-position: 0 24px;
+}
+
+button.enable-toggle-status-bar-item.toggled-on:active {
+    background-position: 32px 24px;
+}
+
+#scripts-pause-on-exceptions-status-bar-item {
+    background-image: url(Images/pauseOnExceptionButtons.png);
+}
+
+#scripts-pause-on-exceptions-status-bar-item:active {
+    background-position: 32px 0;
+}
+
+#scripts-pause-on-exceptions-status-bar-item.toggled-on {
+    background-position: 0 24px;
+}
+
+#scripts-pause-on-exceptions-status-bar-item.toggled-on:active {
+    background-position: 32px 24px;
+}
+
+#scripts-status-bar {
+    position: absolute;
+    top: -1px;
+    left: 0;
+    right: 0;
+    height: 24px;
+}
+
+#scripts-files {
+    max-width: 250px;
+}
+
+#scripts-functions {
+    max-width: 150px;
+}
+
+#scripts-status-bar .status-bar-item img {
+    margin-top: 2px;
+}
+
+#scripts-back img {
+    content: url(Images/back.png);
+}
+
+#scripts-forward img {
+    content: url(Images/forward.png);
+}
+
+#scripts-pause img {
+    content: url(Images/debuggerPause.png);
+}
+
+#scripts-pause.paused img {
+    content: url(Images/debuggerContinue.png);
+}
+
+#scripts-step-over img {
+    content: url(Images/debuggerStepOver.png);
+}
+
+#scripts-step-into img {
+    content: url(Images/debuggerStepInto.png);
+}
+
+#scripts-step-out img {
+    content: url(Images/debuggerStepOut.png);
+}
+
+#scripts-debugger-status {
+    position: absolute;
+    line-height: 24px;
+    top: 0;
+    right: 8px;
+}
+
+#scripts-sidebar-resizer-widget {
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    right: 225px;
+    width: 16px;
+    cursor: col-resize;
+    background-image: url(Images/statusbarResizerHorizontal.png);
+    background-repeat: no-repeat;
+    background-position: center;
+}
+
+#scripts-sidebar-buttons {
+    position: absolute;
+    right: 0;
+    top: 0;
+    bottom: 0;
+    width: 225px;
+    overflow: hidden;
+    border-left: 1px solid rgb(64%, 64%, 64%);
+}
+
+#script-resource-views {
+    display: block;
+    overflow: auto;
+    padding: 0;
+    position: absolute;
+    top: 23px;
+    left: 0;
+    right: 225px;
+    bottom: 0;
+}
+
+.script-view {
+    display: none;
+    overflow: hidden;
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+}
+
+.script-view.visible {
+    display: block;
+}
+
+#scripts-sidebar {
+    position: absolute;
+    top: 23px;
+    right: 0;
+    bottom: 0;
+    width: 225px;
+    background-color: rgb(245, 245, 245);
+    border-left: 1px solid rgb(64%, 64%, 64%);
+    cursor: default;
+    overflow: auto;
+}
+
+#resources-larger-resources-status-bar-item {
+    background-image: url(Images/largerResourcesButtons.png);
+}
+
+#resources-larger-resources-status-bar-item:active {
+    background-position: 32px 0;
+}
+
+#resources-larger-resources-status-bar-item.toggled-on {
+    background-position: 0 24px;
+}
+
+#resources-larger-resources-status-bar-item.toggled-on:active {
+    background-position: 32px 24px;
+}
+
+#resources-container {
+    position: absolute;
+    top: 0;
+    left: 0;
+    bottom: 0;
+    right: 0;
+    border-right: 0 none transparent;
+    overflow-y: auto;
+    overflow-x: hidden;
+}
+
+#resources-container.viewing-resource {
+    right: auto;
+    width: 200px;
+    border-right: 1px solid rgb(64%, 64%, 64%);
+}
+
+#resources-container.viewing-resource #resources-sidebar {
+    width: 100%;
+    border-right: 0 none transparent;
+}
+
+#resources-sidebar {
+    min-height: 100%;
+    bottom: auto;
+    overflow: visible;
+}
+
+#resources-container-content {
+    position: absolute;
+    top: 0;
+    right: 0;
+    left: 200px;
+    min-height: 100%;
+}
+
+#resources-container.viewing-resource #resources-container-content {
+    display: none;
+}
+
+#resources-summary {
+    position: absolute;
+    padding-top: 20px;
+    top: 0;
+    left: 0;
+    right: 0;
+    height: 93px;
+    margin-left: -1px;
+    border-left: 1px solid rgb(102, 102, 102);
+    background-color: rgb(101, 111, 130);
+    background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0)), to(rgba(0, 0, 0, 0.5)));
+    background-repeat: repeat-x;
+    background-position: bottom;
+    text-align: center;
+    text-shadow: black 0 1px 1px;
+    white-space: nowrap;
+    color: white;
+    -webkit-background-size: 1px 6px;
+    -webkit-background-origin: padding;
+    -webkit-background-clip: padding;
+}
+
+#resources-graph-legend {
+    margin-top: -10px;
+    padding-left: 15px;
+}
+
+.resources-graph-legend-item {
+    display: inline-block;
+    font-weight: bold;
+    margin-right: 15px;
+    vertical-align: top;
+}
+
+.resources-graph-legend-item.total {
+    margin-left: 10px;
+}
+
+.resources-graph-legend-label {
+    display: inline-block;
+    text-align: left;
+}
+
+.resources-graph-legend-header {
+    font-size: 12px;
+}
+
+.resources-graph-legend-value {
+    font-size: 10px;
+}
+
+.resources-graph-legend-swatch {
+    vertical-align: top;
+    margin-top: 1px;
+    margin-right: 3px;
+}
+
+#resources-dividers {
+    position: absolute;
+    left: 0;
+    right: 0;
+    height: 100%;
+    top: 0;
+    z-index: -100;
+}
+
+#resources-dividers-label-bar {
+    position: absolute;
+    top: 93px;
+    left: 0px;
+    right: 0;
+    background-color: rgba(255, 255, 255, 0.8);
+    background-clip: padding;
+    border-bottom: 1px solid rgba(0, 0, 0, 0.3);
+    height: 20px;
+    z-index: 200;
+}
+
+.resources-divider {
+    position: absolute;
+    width: 1px;
+    top: 0;
+    bottom: 0;
+    background-color: rgba(0, 0, 0, 0.1);
+}
+
+.resources-divider.last {
+    background-color: transparent;
+}
+
+.resources-divider-label {
+    position: absolute;
+    top: 4px;
+    right: 3px;
+    font-size: 9px;
+    color: rgb(50%, 50%, 50%);
+    white-space: nowrap;
+}
+
+.resources-graph-label {
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    margin: auto -7px;
+    height: 13px;
+    line-height: 13px;
+    font-size: 9px;
+    color: rgba(0, 0, 0, 0.75);
+    text-shadow: rgba(255, 255, 255, 0.25) 1px 0 0, rgba(255, 255, 255, 0.25) -1px 0 0, rgba(255, 255, 255, 0.333) 0 1px 0, rgba(255, 255, 255, 0.25) 0 -1px 0;
+    z-index: 150;
+    overflow: hidden;
+    text-align: center;
+    font-weight: bold;
+    opacity: 0;
+    -webkit-transition: opacity 250ms ease-in-out;
+}
+
+.resources-graph-side:hover .resources-graph-label {
+    opacity: 1;
+}
+
+.resources-graph-label:empty {
+    display: none;
+}
+
+.resources-graph-label.waiting {
+    margin-right: 5px;
+}
+
+.resources-graph-label.before {
+    color: rgba(0, 0, 0, 0.7);
+    text-shadow: none;
+    text-align: right;
+    margin-right: 2px;
+}
+
+.resources-graph-label.before::after {
+    padding-left: 2px;
+    height: 6px;
+    content: url(Images/graphLabelCalloutLeft.png);
+}
+
+.resources-graph-label.after {
+    color: rgba(0, 0, 0, 0.7);
+    text-shadow: none;
+    text-align: left;
+    margin-left: 2px;
+}
+
+.resources-graph-label.after::before {
+    padding-right: 2px;
+    height: 6px;
+    content: url(Images/graphLabelCalloutRight.png);
+}
+
+.resources-graph-bar {
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    margin: auto -7px;
+    border-width: 6px 7px;
+    height: 13px;
+    min-width: 14px;
+    opacity: 0.65;
+    -webkit-border-image: url(Images/timelinePillGray.png) 6 7 6 7;
+}
+
+.resources-graph-bar.waiting {
+    opacity: 0.35;
+}
+
+.resource-cached .resources-graph-bar {
+    -webkit-border-image: url(Images/timelineHollowPillGray.png) 6 7 6 7;
+}
+
+.resources-category-documents .resources-graph-bar {
+    -webkit-border-image: url(Images/timelinePillBlue.png) 6 7 6 7;
+}
+
+.resources-category-documents.resource-cached .resources-graph-bar {
+    -webkit-border-image: url(Images/timelineHollowPillBlue.png) 6 7 6 7;
+}
+
+.resources-category-stylesheets .resources-graph-bar {
+    -webkit-border-image: url(Images/timelinePillGreen.png) 6 7 6 7;
+}
+
+.resources-category-stylesheets.resource-cached .resources-graph-bar {
+    -webkit-border-image: url(Images/timelineHollowPillGreen.png) 6 7 6 7;
+}
+
+.resources-category-images .resources-graph-bar {
+    -webkit-border-image: url(Images/timelinePillPurple.png) 6 7 6 7;
+}
+
+.resources-category-images.resource-cached .resources-graph-bar {
+    -webkit-border-image: url(Images/timelineHollowPillPurple.png) 6 7 6 7;
+}
+
+.resources-category-fonts .resources-graph-bar {
+    -webkit-border-image: url(Images/timelinePillRed.png) 6 7 6 7;
+}
+
+.resources-category-fonts.resource-cached .resources-graph-bar {
+    -webkit-border-image: url(Images/timelineHollowPillRed.png) 6 7 6 7;
+}
+
+.resources-category-scripts .resources-graph-bar {
+    -webkit-border-image: url(Images/timelinePillOrange.png) 6 7 6 7;
+}
+
+.resources-category-scripts.resource-cached .resources-graph-bar {
+    -webkit-border-image: url(Images/timelineHollowPillOrange.png) 6 7 6 7;
+}
+
+.resources-category-xhr .resources-graph-bar {
+    -webkit-border-image: url(Images/timelinePillYellow.png) 6 7 6 7;
+}
+
+.resources-category-xhr.resource-cached .resources-graph-bar {
+    -webkit-border-image: url(Images/timelineHollowPillYellow.png) 6 7 6 7;
+}
+
+.tip-button {
+    background-image: url(Images/tipIcon.png);
+    border: none;
+    width: 16px;
+    height: 16px;
+    float: right;
+    background-color: transparent;
+    margin-top: 1px;
+}
+
+.tip-button:active {
+    background-image: url(Images/tipIconPressed.png);
+}
+
+.tip-balloon {
+    position: absolute;
+    left: 145px;
+    top: -5px;
+    z-index: 1000;
+    border-width: 51px 15px 18px 37px;
+    -webkit-border-image: url(Images/tipBalloon.png) 51 15 18 37;
+    width: 265px;
+}
+
+.tip-balloon.bottom {
+    position: absolute;
+    left: 145px;
+    top: auto;
+    bottom: -7px;
+    z-index: 1000;
+    border-width: 18px 15px 51px 37px;
+    -webkit-border-image: url(Images/tipBalloonBottom.png) 18 15 51 37;
+}
+
+.tip-balloon-content {
+    margin-top: -40px;
+    margin-bottom: -2px;
+    margin-left: 2px;
+}
+
+.tip-balloon.bottom .tip-balloon-content {
+    margin-top: -10px;
+    margin-bottom: -35px;
+}
+
+#resource-views {
+    position: absolute;
+    top: 0;
+    right: 0;
+    left: 200px;
+    bottom: 0;
+}
+
+.source-view-frame {
+    width: 100%;
+    height: 100%;
+}
+
+.sidebar-resizer-vertical {
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    width: 5px;
+    z-index: 500;
+    cursor: col-resize;
+}
+
+.sidebar-tree, .sidebar-tree .children {
+    position: relative;
+    padding: 0;
+    margin: 0;
+    list-style: none;
+    font-size: 11px;
+}
+
+.sidebar-tree-section {
+    position: relative;
+    height: 18px;
+    padding: 4px 10px 6px 10px;
+    white-space: nowrap;
+    margin-top: 1px;
+    color: rgb(92, 110, 129);
+    font-weight: bold;
+    text-shadow: rgba(255, 255, 255, 0.75) 0 1px 0;
+}
+
+.sidebar-tree-item {
+    position: relative;
+    height: 36px;
+    padding: 0 5px 0 5px;
+    white-space: nowrap;
+    margin-top: 1px;
+    line-height: 34px;
+    border-top: 1px solid transparent;
+}
+
+.sidebar-tree .children {
+    display: none;
+}
+
+.sidebar-tree .children.expanded {
+    display: block;
+}
+
+.sidebar-tree-section + .children > .sidebar-tree-item {
+    padding-left: 10px !important;
+}
+
+.sidebar-tree-section + .children.small > .sidebar-tree-item {
+    padding-left: 17px !important;
+}
+
+.sidebar-tree > .children > .sidebar-tree-item {
+    padding-left: 37px;
+}
+
+.sidebar-tree > .children > .children > .sidebar-tree-item {
+    padding-left: 37px;
+}
+
+.sidebar-tree.hide-disclosure-buttons > .children {
+    display: none;
+}
+
+.sidebar-tree > .children.hide-disclosure-buttons > .children {
+    display: none;
+}
+
+.sidebar-tree.some-expandable:not(.hide-disclosure-buttons) > .sidebar-tree-item:not(.parent) .icon {
+    margin-left: 16px;
+}
+
+.sidebar-tree-item .disclosure-button {
+    float: left;
+    width: 16px;
+    height: 100%;
+    border: 0;
+    background-color: transparent;
+    background-image: url(Images/disclosureTriangleSmallRight.png);
+    background-repeat: no-repeat;
+    background-position: center;
+    -webkit-apearance: none;
+}
+
+.sidebar-tree.hide-disclosure-buttons .sidebar-tree-item .disclosure-button {
+    display: none;
+}
+
+body.inactive .sidebar-tree-item .disclosure-button {
+    background-image: url(Images/disclosureTriangleSmallRightBlack.png);
+}
+
+body.inactive .sidebar-tree-item.expanded .disclosure-button {
+    background-image: url(Images/disclosureTriangleSmallDownBlack.png);
+}
+
+body.inactive .sidebar-tree-item .disclosure-button:active {
+    background-image: url(Images/disclosureTriangleSmallRightDownBlack.png);
+}
+
+.sidebar-tree-item.selected .disclosure-button {
+    background-image: url(Images/disclosureTriangleSmallRightWhite.png) !important;
+}
+
+.sidebar-tree-item.expanded .disclosure-button {
+    background-image: url(Images/disclosureTriangleSmallDown.png);
+}
+
+.sidebar-tree-item.selected.expanded .disclosure-button {
+    background-image: url(Images/disclosureTriangleSmallDownWhite.png) !important;
+}
+
+.sidebar-tree-item.selected .disclosure-button:active {
+    background-image: url(Images/disclosureTriangleSmallRightDownWhite.png) !important;
+}
+
+.sidebar-tree-item .disclosure-button:active {
+    background-image: url(Images/disclosureTriangleSmallRightDown.png);
+}
+
+.sidebar-tree-item .icon {
+    float: left;
+    width: 32px;
+    height: 32px;
+    margin-top: 1px;
+    margin-right: 3px;
+}
+
+.sidebar-tree-item .status {
+    float: right;
+    height: 16px;
+    margin-top: 9px;
+    margin-left: 4px;
+    line-height: 1em;
+}
+
+.sidebar-tree-item .status:empty {
+    display: none;
+}
+
+.sidebar-tree-item .status .bubble {
+    display: inline-block;
+    height: 14px;
+    min-width: 16px;
+    margin-top: 1px;
+    background-color: rgb(128, 151, 189);
+    vertical-align: middle;
+    white-space: nowrap;
+    padding: 1px 4px;
+    text-align: center;
+    font-size: 11px;
+    font-family: Helvetia, Arial, sans-serif;
+    font-weight: bold;
+    text-shadow: none;
+    color: white;
+    -webkit-border-radius: 7px;
+}
+
+.sidebar-tree-item .status .bubble:empty {
+    display: none;
+}
+
+.sidebar-tree-item.selected .status .bubble {
+    background-color: white !important;
+    color: rgb(132, 154, 190) !important;
+}
+
+:focus .sidebar-tree-item.selected .status .bubble {
+    color: rgb(36, 98, 172) !important;
+}
+
+body.inactive .sidebar-tree-item.selected .status .bubble {
+    color: rgb(159, 159, 159) !important;
+}
+
+.sidebar-tree.small .sidebar-tree-item, .sidebar-tree .children.small .sidebar-tree-item, .sidebar-tree-item.small, .small .resources-graph-side {
+    height: 20px;
+}
+
+.sidebar-tree.small .sidebar-tree-item .icon, .sidebar-tree .children.small .sidebar-tree-item .icon, .sidebar-tree-item.small .icon {
+    width: 16px;
+    height: 16px;
+}
+
+.sidebar-tree.small .sidebar-tree-item .status, .sidebar-tree .children.small .sidebar-tree-item .status, .sidebar-tree-item.small .status {
+    margin-top: 1px;
+}
+
+.sidebar-tree-item.selected {
+    color: white;
+    border-top: 1px solid rgb(145, 160, 192);
+    background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(162, 177, 207)), to(rgb(120, 138, 177)));
+    text-shadow: rgba(0, 0, 0, 0.33) 0 1px 0;
+    font-weight: bold;
+    -webkit-background-origin: padding;
+    -webkit-background-clip: padding;
+}
+
+:focus .sidebar-tree-item.selected {
+    border-top: 1px solid rgb(68, 128, 200);
+    background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(92, 147, 213)), to(rgb(21, 83, 170)));
+}
+
+body.inactive .sidebar-tree-item.selected {
+    border-top: 1px solid rgb(151, 151, 151);
+    background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(180, 180, 180)), to(rgb(138, 138, 138)));
+}
+
+.sidebar-tree-item .titles {
+    position: relative;
+    top: 5px;
+    line-height: 11px;
+    padding-bottom: 1px;
+    text-overflow: ellipsis;
+    overflow: hidden;
+    white-space: nowrap;
+}
+
+.sidebar-tree-item .titles.no-subtitle {
+    top: 10px;
+}
+
+.sidebar-tree.small .sidebar-tree-item .titles, .sidebar-tree .children.small .sidebar-tree-item .titles, .sidebar-tree-item.small .titles {
+    top: 2px;
+    line-height: normal;
+}
+
+.sidebar-tree:not(.small) .sidebar-tree-item:not(.small) .title::after, .sidebar-tree .children:not(.small) .sidebar-tree-item .title::after {
+    content: "\A";
+    white-space: pre;
+}
+
+.sidebar-tree-item .subtitle {
+    font-size: 9px;
+    color: rgba(0, 0, 0, 0.7);
+}
+
+.sidebar-tree.small .sidebar-tree-item .subtitle, .sidebar-tree .children.small .sidebar-tree-item .subtitle, .sidebar-tree-item.small .subtitle {
+    display: none;
+}
+
+.sidebar-tree-item.selected .subtitle {
+    color: rgba(255, 255, 255, 0.9);
+}
+
+#resources-graphs {
+    position: absolute;
+    left: 0;
+    right: 0;
+    max-height: 100%;
+    top: 112px;
+}
+
+.resources-graph-side {
+    position: relative;
+    height: 36px;
+    padding: 0 5px;
+    white-space: nowrap;
+    margin-top: 1px;
+    border-top: 1px solid transparent;
+    overflow: hidden;
+}
+
+.resources-graph-bar-area {
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    right: 8px;
+    left: 9px;
+}
+
+#resources-container:not(.viewing-resource) .resource-sidebar-tree-item:nth-of-type(2n) {
+    background-color: rgba(0, 0, 0, 0.05);
+}
+
+#resources-container:not(.viewing-resource) .resources-graph-side:nth-of-type(2n) {
+    background-color: rgba(0, 0, 0, 0.05);
+}
+
+.resources-time-graph-sidebar-item .icon {
+    content: url(Images/resourcesTimeGraphIcon.png);
+}
+
+.resources-size-graph-sidebar-item .icon {
+    content: url(Images/resourcesSizeGraphIcon.png);
+}
+
+.resources-size-graph-sidebar-item .icon {
+    content: url(Images/resourcesSizeGraphIcon.png);
+}
+
+.resource-sidebar-tree-item .icon {
+    content: url(Images/resourcePlainIcon.png);
+}
+
+.children.small .resource-sidebar-tree-item .icon {
+    content: url(Images/resourcePlainIconSmall.png);
+}
+
+.resource-sidebar-tree-item.resources-category-documents .icon {
+    content: url(Images/resourceDocumentIcon.png);
+}
+
+.children.small .resource-sidebar-tree-item.resources-category-documents .icon {
+    content: url(Images/resourceDocumentIconSmall.png);
+}
+
+.resource-sidebar-tree-item.resources-category-stylesheets .icon {
+    content: url(Images/resourceCSSIcon.png);
+}
+
+.children.small .resource-sidebar-tree-item.resources-category-stylesheets .icon {
+    content: url(Images/resourceDocumentIconSmall.png);
+}
+
+.resource-sidebar-tree-item.resources-category-images .icon {
+    position: relative;
+    background-image: url(Images/resourcePlainIcon.png);
+    background-repeat: no-repeat;
+    content: "";
+}
+
+.resource-sidebar-tree-item.resources-category-images .image-resource-icon-preview {
+    position: absolute;
+    margin: auto;
+    top: 3px;
+    bottom: 4px;
+    left: 5px;
+    right: 5px;
+    max-width: 18px;
+    max-height: 21px;
+    min-width: 1px;
+    min-height: 1px;
+}
+
+.children.small .resource-sidebar-tree-item.resources-category-images .icon {
+    background-image: url(Images/resourcePlainIconSmall.png);
+    content: "";
+}
+
+.children.small .resource-sidebar-tree-item.resources-category-images .image-resource-icon-preview {
+    top: 2px;
+    bottom: 1px;
+    left: 3px;
+    right: 3px;
+    max-width: 8px;
+    max-height: 11px;
+}
+
+.resource-sidebar-tree-item.resources-category-fonts .icon {
+    content: url(Images/resourcePlainIcon.png);
+}
+
+.children.small .resource-sidebar-tree-item.resources-category-fonts .icon {
+    content: url(Images/resourcePlainIconSmall.png);
+}
+
+.resource-sidebar-tree-item.resources-category-scripts .icon {
+    content: url(Images/resourceJSIcon.png);
+}
+
+.children.small .resource-sidebar-tree-item.resources-category-scripts .icon {
+    content: url(Images/resourceDocumentIconSmall.png);
+}
+
+.resource-sidebar-tree-item.resources-category-xhr .icon {
+    content: url(Images/resourcePlainIcon.png);
+}
+
+.children.small .resource-sidebar-tree-item.resources-category-xhr .icon {
+    content: url(Images/resourceDocumentIconSmall.png);
+}
+
+.bubble.warning, .console-warning-level .bubble {
+    background-color: rgb(232, 164, 0) !important;
+}
+
+.bubble.error, .console-error-level .bubble {
+    background-color: rgb(216, 35, 35) !important;
+}
+
+.bubble.search-matches {
+    background-image: url(Images/searchSmallWhite.png);
+    background-repeat: no-repeat;
+    background-position: 3px 2px;
+    padding-left: 13px !important;
+}
+
+.sidebar-tree-item.selected .bubble.search-matches {
+    background-image: url(Images/searchSmallBlue.png);
+}
+
+:focus .sidebar-tree-item.selected .bubble.search-matches {
+    background-image: url(Images/searchSmallBrightBlue.png);
+}
+
+body.inactive .sidebar-tree-item.selected .bubble.search-matches {
+    background-image: url(Images/searchSmallGray.png);
+}
+
+/* Profiler Style */
+
+#profile-views {
+    position: absolute;
+    top: 0;
+    right: 0;
+    left: 200px;
+    bottom: 0;
+}
+
+#profile-view-status-bar-items {
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    left: 200px;
+    overflow: hidden;
+    border-left: 1px solid rgb(184, 184, 184);
+    margin-left: -1px;
+}
+
+.profile-sidebar-tree-item .icon {
+    content: url(Images/profileIcon.png);
+}
+
+.profile-sidebar-tree-item.small .icon {
+    content: url(Images/profileSmallIcon.png);
+}
+
+.profile-group-sidebar-tree-item .icon {
+    content: url(Images/profileGroupIcon.png);
+}
+
+.profile-view {
+    display: none;
+    overflow: hidden;
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+}
+
+.profile-view.visible {
+    display: block;
+}
+
+.profile-view .data-grid {
+    border: none;
+    height: 100%;
+}
+
+.profile-view .data-grid th.self-column {
+    text-align: center;
+}
+
+.profile-view .data-grid td.self-column {
+    text-align: right;
+}
+
+.profile-view .data-grid th.total-column {
+    text-align: center;
+}
+
+.profile-view .data-grid td.total-column {
+    text-align: right;
+}
+
+.profile-view .data-grid .calls-column {
+    text-align: center;
+}
+
+.profile-node-file {
+    float: right;
+    color: gray;
+    margin-top: -1px;
+}
+
+.data-grid tr.selected .profile-node-file {
+    color: rgb(33%, 33%, 33%);
+}
+
+.data-grid:focus tr.selected .profile-node-file {
+    color: white;
+}
+
+#record-profile-status-bar-item {
+    background-image: url(Images/recordButtons.png);
+}
+
+#record-profile-status-bar-item:active {
+    background-position: 32px 0;
+}
+
+#record-profile-status-bar-item.toggled-on {
+    background-position: 0 24px;
+}
+
+#record-profile-status-bar-item.toggled-on:active {
+    background-position: 32px 24px;
+}
+
+#node-search-status-bar-item {
+    background-image: url(Images/nodeSearchButtons.png);
+}
+
+#node-search-status-bar-item:active {
+    background-position: 32px 0;
+}
+
+#node-search-status-bar-item.toggled-on {
+    background-position: 0 24px;
+}
+
+#node-search-status-bar-item.toggled-on:active {
+    background-position: 32px 24px;
+}
+
+.percent-time-status-bar-item {
+    background-image: url(Images/percentButtons.png) !important;
+}
+
+.percent-time-status-bar-item:active {
+    background-position: 32px 0;
+}
+
+.percent-time-status-bar-item.toggled-on {
+    background-position: 0 24px;
+}
+
+.percent-time-status-bar-item.toggled-on:active {
+    background-position: 32px 24px;
+}
+
+.focus-profile-node-status-bar-item {
+    background-image: url(Images/focusButtons.png) !important;
+}
+
+.focus-profile-node-status-bar-item:active {
+    background-position: 32px 0;
+}
+
+.exclude-profile-node-status-bar-item {
+    background-image: url(Images/excludeButtons.png) !important;
+}
+
+.exclude-profile-node-status-bar-item:active {
+    background-position: 32px 0;
+}
+
+.reset-profile-status-bar-item {
+    background-image: url(Images/reloadButtons.png) !important;
+}
+
+.reset-profile-status-bar-item:active {
+    background-position: 32px 0;
+}
diff --git a/resources/Inspector/inspector.html b/resources/Inspector/inspector.html
new file mode 100644
index 0000000..db1e28b
--- /dev/null
+++ b/resources/Inspector/inspector.html
@@ -0,0 +1,93 @@
+<!--
+Copyright (C) 2006, 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.
+-->
+<!DOCTYPE html>
+<html>
+<head>
+    <meta http-equiv="content-type" content="text/html; charset=utf-8">
+    <link rel="stylesheet" type="text/css" href="inspector.css">
+    <script type="text/javascript" src="utilities.js"></script>
+    <script type="text/javascript" src="treeoutline.js"></script>
+    <script type="text/javascript" src="inspector.js"></script>
+    <script type="text/javascript" src="Object.js"></script>
+    <script type="text/javascript" src="TextPrompt.js"></script>
+    <script type="text/javascript" src="Placard.js"></script>
+    <script type="text/javascript" src="View.js"></script>
+    <script type="text/javascript" src="Console.js"></script>
+    <script type="text/javascript" src="Resource.js"></script>
+    <script type="text/javascript" src="ResourceCategory.js"></script>
+    <script type="text/javascript" src="Database.js"></script>
+    <script type="text/javascript" src="DOMStorage.js"></script>
+    <script type="text/javascript" src="DOMStorageItemsView.js"></script>
+    <script type="text/javascript" src="DataGrid.js"></script>
+    <script type="text/javascript" src="Script.js"></script>
+    <script type="text/javascript" src="Breakpoint.js"></script>
+    <script type="text/javascript" src="SidebarPane.js"></script>
+    <script type="text/javascript" src="ElementsTreeOutline.js"></script>
+    <script type="text/javascript" src="SidebarTreeElement.js"></script>
+    <script type="text/javascript" src="PropertiesSection.js"></script>
+    <script type="text/javascript" src="ObjectPropertiesSection.js"></script>
+    <script type="text/javascript" src="BreakpointsSidebarPane.js"></script>
+    <script type="text/javascript" src="CallStackSidebarPane.js"></script>
+    <script type="text/javascript" src="ScopeChainSidebarPane.js"></script>
+    <script type="text/javascript" src="MetricsSidebarPane.js"></script>
+    <script type="text/javascript" src="PropertiesSidebarPane.js"></script>
+    <script type="text/javascript" src="StylesSidebarPane.js"></script>
+    <script type="text/javascript" src="Panel.js"></script>
+    <script type="text/javascript" src="PanelEnablerView.js"></script>
+    <script type="text/javascript" src="ElementsPanel.js"></script>
+    <script type="text/javascript" src="ResourcesPanel.js"></script>
+    <script type="text/javascript" src="ScriptsPanel.js"></script>
+    <script type="text/javascript" src="DatabasesPanel.js"></script>
+    <script type="text/javascript" src="ProfilesPanel.js"></script>
+    <script type="text/javascript" src="ResourceView.js"></script>
+    <script type="text/javascript" src="SourceFrame.js"></script>
+    <script type="text/javascript" src="SourceView.js"></script>
+    <script type="text/javascript" src="FontView.js"></script>
+    <script type="text/javascript" src="ImageView.js"></script>
+    <script type="text/javascript" src="DatabaseTableView.js"></script>
+    <script type="text/javascript" src="DatabaseQueryView.js"></script>
+    <script type="text/javascript" src="ScriptView.js"></script>
+    <script type="text/javascript" src="ProfileView.js"></script>
+</head>
+<body class="detached">
+    <div id="toolbar">
+        <div class="toolbar-item close"><button id="close-button"></button></div>
+        <div class="toolbar-item flexable-space"></div>
+        <div class="toolbar-item hidden" id="search-results-matches"></div>
+        <div class="toolbar-item"><input id="search" type="search" incremental results="0"><div id="search-toolbar-label" class="toolbar-label"></div></div>
+    </div>
+    <div id="main">
+        <div id="main-panels" tabindex="0"></div>
+        <div id="main-status-bar" class="status-bar"><div id="anchored-status-bar-items"><button id="dock-status-bar-item" class="status-bar-item toggled"></button><button id="console-status-bar-item" class="status-bar-item"></button><div id="error-warning-count" class="hidden"></div></div></div>
+    </div>
+    <div id="console">
+        <div id="console-messages"><div id="console-prompt"><br></div></div>
+        <div id="console-status-bar" class="status-bar"><div id="other-console-status-bar-items"><button id="clear-console-status-bar-item" class="status-bar-item"></button></div></div>
+    </div>
+</body>
+</html>
diff --git a/resources/Inspector/inspector.js b/resources/Inspector/inspector.js
new file mode 100644
index 0000000..759684f
--- /dev/null
+++ b/resources/Inspector/inspector.js
@@ -0,0 +1,1303 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc.  All rights reserved.
+ * Copyright (C) 2007 Matt Lilek (pewtermoose@gmail.com).
+ *
+ * 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.
+ */
+
+var Preferences = {
+    ignoreWhitespace: true,
+    showUserAgentStyles: true,
+    maxInlineTextChildLength: 80,
+    minConsoleHeight: 75,
+    minSidebarWidth: 100,
+    minElementsSidebarWidth: 200,
+    minScriptsSidebarWidth: 200,
+    showInheritedComputedStyleProperties: false,
+    styleRulesExpandedState: {},
+    showMissingLocalizedStrings: false
+}
+
+var WebInspector = {
+    resources: [],
+    resourceURLMap: {},
+    missingLocalizedStrings: {},
+
+    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 = document.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();
+                }
+            }
+        }
+    },
+
+    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) {
+            InspectorController.attach();
+            body.removeStyleClass("detached");
+            body.addStyleClass("attached");
+            dockToggleButton.title = WebInspector.UIString("Undock into separate window.");
+        } else {
+            InspectorController.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 hoveredDOMNode()
+    {
+        return this._hoveredDOMNode;
+    },
+
+    set hoveredDOMNode(x)
+    {
+        if (objectsAreSame(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) {
+            InspectorController.highlightDOMNode(this._hoveredDOMNode);
+            this.showingDOMNodeHighlight = true;
+        } else {
+            InspectorController.hideDOMNodeHighlight();
+            this.showingDOMNodeHighlight = false;
+        }
+    }
+}
+
+WebInspector.loaded = function()
+{
+    var platform = InspectorController.platform();
+    document.body.addStyleClass("platform-" + platform);
+
+    this.console = new WebInspector.Console();
+    this.panels = {
+        elements: new WebInspector.ElementsPanel(),
+        resources: new WebInspector.ResourcesPanel(),
+        // We don't use next tabs, so don't show them.
+        //scripts: new WebInspector.ScriptsPanel(),
+        //profiles: new WebInspector.ProfilesPanel(),
+        //databases: new WebInspector.DatabasesPanel()
+    };
+
+    var toolbarElement = document.getElementById("toolbar");
+    var previousToolbarItem = toolbarElement.children[0];
+
+    for (var panelName in this.panels) {
+        var panel = this.panels[panelName];
+        var panelToolbarItem = panel.toolbarItem;
+        panelToolbarItem.addEventListener("click", this._toolbarItemClicked.bind(this));
+        if (previousToolbarItem)
+            toolbarElement.insertBefore(panelToolbarItem, previousToolbarItem.nextSibling);
+        else
+            toolbarElement.insertBefore(panelToolbarItem, toolbarElement.firstChild);
+        previousToolbarItem = panelToolbarItem;
+    }
+
+    this.currentPanel = this.panels.elements;
+
+    this.resourceCategories = {
+        documents: new WebInspector.ResourceCategory(WebInspector.UIString("Documents"), "documents"),
+        stylesheets: new WebInspector.ResourceCategory(WebInspector.UIString("Stylesheets"), "stylesheets"),
+        images: new WebInspector.ResourceCategory(WebInspector.UIString("Images"), "images"),
+        scripts: new WebInspector.ResourceCategory(WebInspector.UIString("Scripts"), "scripts"),
+        xhr: new WebInspector.ResourceCategory(WebInspector.UIString("XHR"), "xhr"),
+        fonts: new WebInspector.ResourceCategory(WebInspector.UIString("Fonts"), "fonts"),
+        other: new WebInspector.ResourceCategory(WebInspector.UIString("Other"), "other")
+    };
+
+    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), true);
+    document.addEventListener("keyup", this.documentKeyUp.bind(this), true);
+    document.addEventListener("beforecopy", this.documentCanCopy.bind(this), true);
+    document.addEventListener("copy", this.documentCopy.bind(this), true);
+
+    var mainPanelsElement = document.getElementById("main-panels");
+    mainPanelsElement.handleKeyEvent = this.mainKeyDown.bind(this);
+    mainPanelsElement.handleKeyUpEvent = this.mainKeyUp.bind(this);
+    mainPanelsElement.handleCopyEvent = this.mainCopy.bind(this);
+
+    // Focus the mainPanelsElement in a timeout so it happens after the initial focus,
+    // so it doesn't get reset to the first toolbar button. This initial focus happens
+    // on Mac when the window is made key and the WebHTMLView becomes the first responder.
+    setTimeout(function() { WebInspector.currentFocusElement = mainPanelsElement }, 0);
+
+    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.console.show.bind(this.console), false);
+    this._updateErrorAndWarningCounts();
+
+    var searchField = document.getElementById("search");
+    searchField.addEventListener("keydown", this.searchKeyDown.bind(this), false);
+    searchField.addEventListener("keyup", this.searchKeyUp.bind(this), false);
+    searchField.addEventListener("search", this.performSearch.bind(this), false); // when the search is emptied
+
+    document.getElementById("toolbar").addEventListener("mousedown", this.toolbarDragStart, true);
+    document.getElementById("close-button").addEventListener("click", this.close, true);
+
+    InspectorController.loaded();
+}
+
+var windowLoaded = function()
+{
+    var localizedStringsURL = InspectorController.localizedStringsURL();
+    if (localizedStringsURL) {
+        var localizedStringsScriptElement = document.createElement("script");
+        localizedStringsScriptElement.addEventListener("load", WebInspector.loaded.bind(WebInspector), false);
+        localizedStringsScriptElement.type = "text/javascript";
+        localizedStringsScriptElement.src = localizedStringsURL;
+        document.getElementsByTagName("head").item(0).appendChild(localizedStringsScriptElement);
+    } else
+        WebInspector.loaded();
+
+    window.removeEventListener("load", windowLoaded, false);
+    delete windowLoaded;
+};
+
+window.addEventListener("load", windowLoaded, false);
+
+WebInspector.windowUnload = function(event)
+{
+    InspectorController.windowUnloading();
+}
+
+WebInspector.windowResize = function(event)
+{
+    if (this.currentPanel && this.currentPanel.resize)
+        this.currentPanel.resize();
+}
+
+WebInspector.windowFocused = function(event)
+{
+    if (event.target.nodeType === Node.DOCUMENT_NODE)
+        document.body.removeStyleClass("inactive");
+}
+
+WebInspector.windowBlured = function(event)
+{
+    if (event.target.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)
+{
+    InspectorController.closeWindow();
+}
+
+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 (anchor.href in WebInspector.resourceURLMap) {
+            if (anchor.hasStyleClass("webkit-html-external-link")) {
+                anchor.removeStyleClass("webkit-html-external-link");
+                anchor.addStyleClass("webkit-html-resource-link");
+            }
+
+            WebInspector.showResourceForURL(anchor.href, anchor.lineNumber, anchor.preferredPanel);
+        } else {
+            var profileStringRegEx = new RegExp("webkit-profile://.+/([0-9]+)");
+            var profileString = profileStringRegEx.exec(anchor.href);
+            if (profileString)
+                WebInspector.showProfileById(profileString[1])
+        }
+    }
+
+    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)
+        return;
+    if (this.currentFocusElement.handleKeyEvent)
+        this.currentFocusElement.handleKeyEvent(event);
+    else if (this.currentFocusElement.id && this.currentFocusElement.id.length && WebInspector[this.currentFocusElement.id + "KeyDown"])
+        WebInspector[this.currentFocusElement.id + "KeyDown"](event);
+
+    if (!event.handled) {
+        var isMac = InspectorController.platform().indexOf("mac-") === 0;
+
+        switch (event.keyIdentifier) {
+            case "U+001B": // Escape key
+                this.console.visible = !this.console.visible;
+                event.preventDefault();
+                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) {
+                    var searchField = document.getElementById("search");
+                    searchField.focus();
+                    searchField.select();
+                    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;
+        }
+    }
+}
+
+WebInspector.documentKeyUp = function(event)
+{
+    if (!this.currentFocusElement || !this.currentFocusElement.handleKeyUpEvent)
+        return;
+    this.currentFocusElement.handleKeyUpEvent(event);
+}
+
+WebInspector.documentCanCopy = function(event)
+{
+    if (!this.currentFocusElement)
+        return;
+    // Calling preventDefault() will say "we support copying, so enable the Copy menu".
+    if (this.currentFocusElement.handleCopyEvent)
+        event.preventDefault();
+    else if (this.currentFocusElement.id && this.currentFocusElement.id.length && WebInspector[this.currentFocusElement.id + "Copy"])
+        event.preventDefault();
+}
+
+WebInspector.documentCopy = function(event)
+{
+    if (!this.currentFocusElement)
+        return;
+    if (this.currentFocusElement.handleCopyEvent)
+        this.currentFocusElement.handleCopyEvent(event);
+    else if (this.currentFocusElement.id && this.currentFocusElement.id.length && WebInspector[this.currentFocusElement.id + "Copy"])
+        WebInspector[this.currentFocusElement.id + "Copy"](event);
+}
+
+WebInspector.mainKeyDown = function(event)
+{
+    if (this.currentPanel && this.currentPanel.handleKeyEvent)
+        this.currentPanel.handleKeyEvent(event);
+}
+
+WebInspector.mainKeyUp = function(event)
+{
+    if (this.currentPanel && this.currentPanel.handleKeyUpEvent)
+        this.currentPanel.handleKeyUpEvent(event);
+}
+
+WebInspector.mainCopy = function(event)
+{
+    if (this.currentPanel && this.currentPanel.handleCopyEvent)
+        this.currentPanel.handleCopyEvent(event);
+}
+
+WebInspector.animateStyle = function(animations, duration, callback, complete)
+{
+    if (complete === undefined)
+        complete = 0;
+    var slice = (1000 / 30); // 30 frames per second
+
+    var defaultUnit = "px";
+    var propertyUnit = {opacity: ""};
+
+    for (var i = 0; i < animations.length; ++i) {
+        var animation = animations[i];
+        var element = null;
+        var start = null;
+        var current = null;
+        var end = null;
+        for (key in animation) {
+            if (key === "element")
+                element = animation[key];
+            else if (key === "start")
+                start = animation[key];
+            else if (key === "current")
+                current = animation[key];
+            else if (key === "end")
+                end = animation[key];
+        }
+
+        if (!element || !end)
+            continue;
+
+        var computedStyle = element.ownerDocument.defaultView.getComputedStyle(element);
+        if (!start) {
+            start = {};
+            for (key in end)
+                start[key] = parseInt(computedStyle.getPropertyValue(key));
+            animation.start = start;
+        } else if (complete == 0)
+            for (key in start)
+                element.style.setProperty(key, start[key] + (key in propertyUnit ? propertyUnit[key] : defaultUnit));
+
+        if (!current) {
+            current = {};
+            for (key in start)
+                current[key] = start[key];
+            animation.current = current;
+        }
+
+        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;
+        }
+
+        var style = element.style;
+        for (key in end) {
+            var startValue = start[key];
+            var currentValue = current[key];
+            var endValue = end[key];
+            if ((complete + slice) < duration) {
+                var delta = (endValue - startValue) / (duration / slice);
+                var newValue = cubicInOut(complete, startValue, endValue - startValue, duration);
+                style.setProperty(key, newValue + (key in propertyUnit ? propertyUnit[key] : defaultUnit));
+                current[key] = newValue;
+            } else {
+                style.setProperty(key, endValue + (key in propertyUnit ? propertyUnit[key] : defaultUnit));
+            }
+        }
+    }
+
+    if (complete < duration)
+        setTimeout(WebInspector.animateStyle, slice, animations, duration, callback, complete + slice);
+    else if (callback)
+        callback();
+}
+
+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.toggleAttach = function()
+{
+    this.attached = !this.attached;
+}
+
+WebInspector.toolbarDragStart = function(event)
+{
+    if (!WebInspector.attached && InspectorController.platform() !== "mac-leopard")
+        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);
+
+        InspectorController.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.
+        InspectorController.moveByUnrestricted(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.console.show();
+}
+
+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.showProfilesPanel = function()
+{
+    this.currentPanel = this.panels.profiles;
+}
+
+WebInspector.showDatabasesPanel = function()
+{
+    this.currentPanel = this.panels.databases;
+}
+
+WebInspector.addResource = function(resource)
+{
+    this.resources.push(resource);
+    this.resourceURLMap[resource.url] = resource;
+
+    if (resource.mainResource) {
+        this.mainResource = resource;
+        this.panels.elements.reset();
+    }
+
+    if (this.panels.resources)
+        this.panels.resources.addResource(resource);
+}
+
+WebInspector.removeResource = function(resource)
+{
+    resource.category.removeResource(resource);
+    delete this.resourceURLMap[resource.url];
+
+    this.resources.remove(resource, true);
+
+    if (this.panels.resources)
+        this.panels.resources.removeResource(resource);
+}
+
+WebInspector.addDatabase = function(database)
+{
+    this.panels.databases.addDatabase(database);
+}
+
+WebInspector.addDOMStorage = function(domStorage)
+{
+    this.panels.databases.addDOMStorage(domStorage);
+}
+
+WebInspector.debuggerWasEnabled = function()
+{
+    this.panels.scripts.debuggerWasEnabled();
+}
+
+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.failedToParseScriptSource = function(sourceURL, source, startingLine, errorLine, errorMessage)
+{
+    this.panels.scripts.addScript(null, sourceURL, source, startingLine, errorLine, errorMessage);
+}
+
+WebInspector.pausedScript = function()
+{
+    this.panels.scripts.debuggerPaused();
+}
+
+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.hoveredDOMNode = null;
+
+    delete this.mainResource;
+
+    this.console.clearMessages();
+}
+
+WebInspector.inspectedWindowCleared = function(inspectedWindow)
+{
+    this.panels.elements.inspectedWindowCleared(inspectedWindow);
+}
+
+WebInspector.resourceURLChanged = function(resource, oldURL)
+{
+    delete this.resourceURLMap[oldURL];
+    this.resourceURLMap[resource.url] = resource;
+}
+
+WebInspector.addMessageToConsole = function(msg)
+{
+    this.console.addMessage(msg);
+}
+
+WebInspector.addProfile = function(profile)
+{
+    this.panels.profiles.addProfile(profile);
+}
+
+WebInspector.setRecordingProfile = function(isProfiling)
+{
+    this.panels.profiles.setRecordingProfile(isProfiling);
+}
+
+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(node)
+{
+    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)
+{
+    if (!url)
+        return "";
+    var resource = this.resourceURLMap[url];
+    if (resource)
+        return resource.displayName;
+    return url.trimURL(WebInspector.mainResource ? WebInspector.mainResource.domain : "");
+}
+
+WebInspector.resourceForURL = function(url)
+{
+    if (url in this.resourceURLMap)
+        return this.resourceURLMap[url];
+
+    // No direct match found. Search for resources that contain
+    // a substring of the URL.
+    for (var resourceURL in this.resourceURLMap) {
+        if (resourceURL.hasSubstring(url))
+            return this.resourceURLMap[resourceURL];
+    }
+
+    return null;
+}
+
+WebInspector.showResourceForURL = function(url, line, preferredPanel)
+{
+    var resource = this.resourceForURL(url);
+    if (!resource)
+        return false;
+
+    if (preferredPanel && preferredPanel in WebInspector.panels) {
+        var panel = this.panels[preferredPanel];
+        if (!("showResource" in panel))
+            panel = null;
+        else if ("canShowResource" in panel && !panel.canShowResource(resource))
+            panel = null;
+    }
+
+    this.currentPanel = panel || this.panels.resources;
+    if (!this.currentPanel)
+        return false;
+    this.currentPanel.showResource(resource, line);
+    return true;
+}
+
+WebInspector.linkifyStringAsFragment = function(string)
+{
+    var container = document.createDocumentFragment();
+    var linkStringRegEx = new RegExp("(?:[a-zA-Z][a-zA-Z0-9+.-]{2,}://|www\\.)[\\w$\\-_+*'=\\|/\\\\(){}[\\]%@&#~,:;.!?]{2,}[\\w$\\-_+*=\\|/\\\\({%@&#~]");
+
+    while (string) {
+        var linkString = linkStringRegEx.exec(string);
+        if (!linkString)
+            break;
+
+        linkString = linkString[0];
+        var title = linkString;
+        var linkIndex = string.indexOf(linkString);
+        var nonLink = string.substring(0, linkIndex);
+        container.appendChild(document.createTextNode(nonLink));
+
+        var profileStringRegEx = new RegExp("webkit-profile://(.+)/[0-9]+");
+        var profileStringMatches = profileStringRegEx.exec(title);
+        var profileTitle;
+        if (profileStringMatches)
+            profileTitle = profileStringMatches[1];
+        if (profileTitle)
+            title = WebInspector.panels.profiles.displayTitleForProfileLink(profileTitle);
+
+        var realURL = (linkString.indexOf("www.") === 0 ? "http://" + linkString : linkString);
+        container.appendChild(WebInspector.linkifyURLAsNode(realURL, title, null, (realURL in WebInspector.resourceURLMap)));
+        string = string.substring(linkIndex + linkString.length, string.length);
+    }
+
+    if (string)
+        container.appendChild(document.createTextNode(string));
+
+    return container;
+}
+
+WebInspector.showProfileById = function(uid) {
+    WebInspector.showProfilesPanel();
+    WebInspector.panels.profiles.showProfileById(uid);
+}
+
+WebInspector.linkifyURLAsNode = function(url, linkText, classes, isExternal)
+{
+    if (!linkText)
+        linkText = url;
+    classes = (classes ? classes + " " : "");
+    classes += isExternal ? "webkit-html-external-link" : "webkit-html-resource-link";
+
+    var a = document.createElement("a");
+    a.href = url;
+    a.className = classes;
+    a.title = url;
+    a.target = "_blank";
+    a.textContent = linkText;
+    
+    return a;
+}
+
+WebInspector.linkifyURL = function(url, linkText, classes, isExternal)
+{
+    // Use the DOM version of this function so as to avoid needing to escape attributes.
+    // FIXME:  Get rid of linkifyURL entirely.
+    return WebInspector.linkifyURLAsNode(url, linkText, classes, isExternal).outerHTML;
+}
+
+WebInspector.addMainEventListeners = function(doc)
+{
+    doc.defaultView.addEventListener("focus", this.windowFocused.bind(this), true);
+    doc.defaultView.addEventListener("blur", this.windowBlured.bind(this), true);
+    doc.addEventListener("click", this.documentClick.bind(this), true);
+}
+
+WebInspector.searchKeyDown = function(event)
+{
+    if (event.keyIdentifier !== "Enter")
+        return;
+
+    // Call preventDefault since this was the Enter key. This prevents a "search" event
+    // from firing for key down. We handle the Enter key on key up in searchKeyUp. This
+    // stops performSearch from being called twice in a row.
+    event.preventDefault();
+}
+
+WebInspector.searchKeyUp = function(event)
+{
+    if (event.keyIdentifier !== "Enter")
+        return;
+
+    // Select all of the text so the user can easily type an entirely new query.
+    event.target.select();
+
+    // Only call performSearch if the Enter key was pressed. Otherwise the search
+    // performance is poor because of searching on every key. The search field has
+    // the incremental attribute set, so we still get incremental searches.
+    this.performSearch(event);
+}
+
+WebInspector.performSearch = function(event)
+{
+    var query = event.target.value;
+    var forceSearch = event.keyIdentifier === "Enter";
+
+    if (!query || !query.length || (!forceSearch && query.length < 3)) {
+        delete this.currentQuery;
+
+        for (var panelName in this.panels) {
+            var panel = this.panels[panelName];
+            if (panel.currentQuery && panel.searchCanceled)
+                panel.searchCanceled();
+            delete panel.currentQuery;
+        }
+
+        this.updateSearchMatchesCount();
+
+        return;
+    }
+
+    if (query === this.currentPanel.currentQuery && this.currentPanel.currentQuery === this.currentQuery) {
+        // When this is the same query and a forced search, jump to the next
+        // search result for a good user experience.
+        if (forceSearch && this.currentPanel.jumpToNextSearchResult)
+            this.currentPanel.jumpToNextSearchResult();
+        return;
+    }
+
+    this.currentQuery = query;
+
+    this.updateSearchMatchesCount();
+
+    if (!this.currentPanel.performSearch)
+        return;
+
+    this.currentPanel.currentQuery = query;
+    this.currentPanel.performSearch(query);
+}
+
+WebInspector.updateSearchMatchesCount = function(matches, panel)
+{
+    if (!panel)
+        panel = this.currentPanel;
+
+    panel.currentSearchMatches = matches;
+
+    if (panel !== this.currentPanel)
+        return;
+
+    if (!this.currentPanel.currentQuery) {
+        document.getElementById("search-results-matches").addStyleClass("hidden");
+        return;
+    }
+
+    if (matches) {
+        if (matches === 1)
+            var matchesString = WebInspector.UIString("1 match");
+        else
+            var matchesString = WebInspector.UIString("%d matches", matches);
+    } else
+        var matchesString = WebInspector.UIString("Not Found");
+
+    var matchesToolbarElement = document.getElementById("search-results-matches");
+    matchesToolbarElement.removeStyleClass("hidden");
+    matchesToolbarElement.textContent = matchesString;
+}
+
+WebInspector.UIString = function(string)
+{
+    if (window.localizedStrings && string in window.localizedStrings)
+        string = window.localizedStrings[string];
+    else {
+        if (!(string in this.missingLocalizedStrings)) {
+            console.error("Localized string \"" + string + "\" not found.");
+            this.missingLocalizedStrings[string] = true;
+        }
+
+        if (Preferences.showMissingLocalizedStrings)
+            string += " (not localized)";
+    }
+
+    return String.vsprintf(string, Array.prototype.slice.call(arguments, 1));
+}
+
+WebInspector.isBeingEdited = function(element)
+{
+    return element.__editing;
+}
+
+WebInspector.startEditing = function(element, committedCallback, cancelledCallback, context)
+{
+    if (element.__editing)
+        return;
+    element.__editing = true;
+
+    var oldText = element.textContent;
+    var oldHandleKeyEvent = element.handleKeyEvent;
+
+    element.addStyleClass("editing");
+
+    var oldTabIndex = element.tabIndex;
+    if (element.tabIndex < 0)
+        element.tabIndex = 0;
+
+    function blurEventListener() {
+        editingCommitted.call(element);
+    }
+
+    function cleanUpAfterEditing() {
+        delete this.__editing;
+
+        this.removeStyleClass("editing");
+        this.tabIndex = oldTabIndex;
+        this.scrollTop = 0;
+        this.scrollLeft = 0;
+
+        this.handleKeyEvent = oldHandleKeyEvent;
+        element.removeEventListener("blur", blurEventListener, false);
+
+        if (element === WebInspector.currentFocusElement || element.isAncestor(WebInspector.currentFocusElement))
+            WebInspector.currentFocusElement = WebInspector.previousFocusElement;
+    }
+
+    function editingCancelled() {
+        this.innerText = oldText;
+
+        cleanUpAfterEditing.call(this);
+
+        cancelledCallback(this, context);
+    }
+
+    function editingCommitted() {
+        cleanUpAfterEditing.call(this);
+
+        committedCallback(this, this.textContent, oldText, context);
+    }
+
+    element.handleKeyEvent = function(event) {
+        if (oldHandleKeyEvent)
+            oldHandleKeyEvent(event);
+        if (event.handled)
+            return;
+
+        if (event.keyIdentifier === "Enter") {
+            editingCommitted.call(element);
+            event.preventDefault();
+        } else if (event.keyCode === 27) { // Escape key
+            editingCancelled.call(element);
+            event.preventDefault();
+            event.handled = true;
+        }
+    }
+
+    element.addEventListener("blur", blurEventListener, false);
+
+    WebInspector.currentFocusElement = element;
+}
+
+WebInspector._toolbarItemClicked = function(event)
+{
+    var toolbarItem = event.currentTarget;
+    this.currentPanel = toolbarItem.panel;
+}
+
+// This table maps MIME types to the Resource.Types which are valid for them.
+// The following line:
+//    "text/html":                {0: 1},
+// means that text/html is a valid MIME type for resources that have type
+// WebInspector.Resource.Type.Document (which has a value of 0).
+WebInspector.MIMETypes = {
+    "text/html":                   {0: true},
+    "text/xml":                    {0: true},
+    "text/plain":                  {0: true},
+    "application/xhtml+xml":       {0: true},
+    "text/css":                    {1: true},
+    "text/xsl":                    {1: true},
+    "image/jpeg":                  {2: true},
+    "image/png":                   {2: true},
+    "image/gif":                   {2: true},
+    "image/bmp":                   {2: true},
+    "image/x-icon":                {2: true},
+    "image/x-xbitmap":             {2: true},
+    "font/ttf":                    {3: true},
+    "font/opentype":               {3: true},
+    "application/x-font-type1":    {3: true},
+    "application/x-font-ttf":      {3: true},
+    "application/x-truetype-font": {3: true},
+    "text/javascript":             {4: true},
+    "text/ecmascript":             {4: true},
+    "application/javascript":      {4: true},
+    "application/ecmascript":      {4: true},
+    "application/x-javascript":    {4: true},
+    "text/javascript1.1":          {4: true},
+    "text/javascript1.2":          {4: true},
+    "text/javascript1.3":          {4: true},
+    "text/jscript":                {4: true},
+    "text/livescript":             {4: true},
+}
+
+
+// Stubs for some methods called in ElementsPanel.js which are not yet 
+// supported by Chrome version of InspectorController
+InspectorController.wrapCallback = function f(a) {
+  return a;
+};
+
+InspectorController.searchingForNode = function() {
+  return false;
+};
+
+InspectorController.toggleNodeSearch = function() {
+};
+
+InspectorController.isWindowVisible = function() {
+  return true;
+};
+
+InspectorController.closeWindow =  function() {
+};
+
+InspectorController.clearMessages = function() {
+};
+
+InspectorController.setAttachedWindowHeight = function(height) {
+};
+
+InspectorController.moveByUnrestricted = function(x, y) {
+};
diff --git a/resources/Inspector/quirks-overrides.css b/resources/Inspector/quirks-overrides.css
new file mode 100644
index 0000000..b0300ee
--- /dev/null
+++ b/resources/Inspector/quirks-overrides.css
@@ -0,0 +1,12 @@
+/* Copyright 2008 Google Inc. All Rights Reserved. */
+/* Author: ojan@google.com (Ojan Vafai) */
+
+/* These styles override the default styling for HTML elements in quirks-mode
+   as defined in WebCore/css/quirks.css. So far we have used this file exclusively for
+   making our form elements match Firefoxes. If we find other needs for this
+   file we should seriously consider if this is the right place of them. */
+
+textarea {
+  /* Matches IE's text offsets in quirksmode (causes text to wrap the same as IE). */
+  padding: 2px 0 0 2px;
+}
diff --git a/resources/Inspector/treeoutline.js b/resources/Inspector/treeoutline.js
new file mode 100644
index 0000000..579e7fb
--- /dev/null
+++ b/resources/Inspector/treeoutline.js
@@ -0,0 +1,846 @@
+/*
+ * 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;
+}
+
+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);
+
+    child.deselect();
+
+    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.findTreeElement = function(representedObject, isAncestor, getParent, equal)
+{
+    if (!representedObject)
+        return null;
+
+    if (!equal)
+        equal = function(a, b) { return a === b };
+
+    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 (equal(elements[i].representedObject, representedObject))
+                    return elements[i];
+        }
+    }
+
+    if (!isAncestor || !(isAncestor instanceof Function) || !getParent || !(getParent instanceof Function))
+        return null;
+
+    // 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 (equal(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 (equal(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 (equal(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, equal);
+        if (item && item.onpopulate)
+            item.onpopulate(item);
+    }
+
+    // Now that all the ancestors are populated, try to find the representedObject again. This time
+    // without the isAncestor and getParent functions to prevent an infinite recursion if it isn't found.
+    return this.findTreeElement(representedObject, null, null, equal);
+}
+
+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.handleKeyEvent = function(event)
+{
+    if (!this.selectedTreeElement || event.shiftKey || event.metaKey || event.ctrlKey)
+        return false;
+
+    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();
+    }
+
+    return handled;
+}
+
+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(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.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;
+
+    this.selected = false;
+    this.treeOutline.selectedTreeElement = null;
+    if (this._listItemNode)
+        this._listItemNode.removeStyleClass("selected");
+
+    if (this.ondeselect && !supressOnDeselect)
+        this.ondeselect(this);
+}
+
+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;
+}
diff --git a/resources/Inspector/utilities.js b/resources/Inspector/utilities.js
new file mode 100644
index 0000000..8f86504
--- /dev/null
+++ b/resources/Inspector/utilities.js
@@ -0,0 +1,1098 @@
+/*
+ * 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.type = function(obj, win)
+{
+    if (obj === null)
+        return "null";
+
+    var type = typeof obj;
+    if (type !== "object" && type !== "function")
+        return type;
+
+    win = win || window;
+
+    if (obj instanceof win.String)
+        return "string";
+    if (obj instanceof win.Array)
+        return "array";
+    if (obj instanceof win.Boolean)
+        return "boolean";
+    if (obj instanceof win.Number)
+        return "number";
+    if (obj instanceof win.Date)
+        return "date";
+    if (obj instanceof win.RegExp)
+        return "regexp";
+    if (obj instanceof win.Error)
+        return "error";
+    return type;
+}
+
+Object.hasProperties = function(obj)
+{
+    if (typeof obj === "undefined" || typeof obj === "null")
+        return false;
+    for (var name in obj)
+        return true;
+    return false;
+}
+
+Object.describe = function(obj, abbreviated)
+{
+    var type1 = Object.type(obj);
+    var type2 = Object.prototype.toString.call(obj).replace(/^\[object (.*)\]$/i, "$1");
+
+    switch (type1) {
+    case "object":
+        return type2;
+    case "array":
+        return "[" + obj.toString() + "]";
+    case "string":
+        if (obj.length > 100)
+            return "\"" + obj.substring(0, 100) + "\u2026\"";
+        return "\"" + obj + "\"";
+    case "function":
+        var objectText = String(obj);
+        if (!/^function /.test(objectText))
+            objectText = (type2 == "object") ? type1 : type2;
+        else if (abbreviated)
+            objectText = /.*/.exec(obj)[0].replace(/ +$/g, "");
+        return objectText;
+    case "regexp":
+        return String(obj).replace(/([\\\/])/g, "\\$1").replace(/\\(\/[gim]*)$/, "$1").substring(1);
+    default:
+        return String(obj);
+    }
+}
+
+Object.sortedProperties = function(obj)
+{
+    var properties = [];
+    for (var prop in obj)
+        properties.push(prop);
+    properties.sort();
+    return properties;
+}
+
+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(false, 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(false, 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;
+}
+
+Element.prototype.removeStyleClass = function(className) 
+{
+    // Test for the simple case before using a RegExp.
+    if (this.className === className) {
+        this.className = "";
+        return;
+    }
+
+    this.removeMatchingStyleClasses(className.escapeForRegExp());
+}
+
+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 before using a RegExp.
+    if (this.className === className)
+        return true;
+    var regex = new RegExp("(^|\\s)" + className.escapeForRegExp() + "($|\\s)");
+    return regex.test(this.className);
+}
+
+Node.prototype.enclosingNodeOrSelfWithNodeNameInArray = function(nameArray)
+{
+    for (var node = this; node && !objectsAreSame(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 && !objectsAreSame(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()
+{
+    while (this.firstChild) 
+        this.removeChild(this.firstChild);        
+}
+
+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;
+    return total;
+});
+
+Element.prototype.__defineGetter__("totalOffsetTop", function()
+{
+    var total = 0;
+    for (var element = this; element; element = element.offsetParent)
+        total += element.offsetTop;
+    return total;
+});
+
+Element.prototype.firstChildSkippingWhitespace = firstChildSkippingWhitespace;
+Element.prototype.lastChildSkippingWhitespace = lastChildSkippingWhitespace;
+
+Node.prototype.isWhitespace = isNodeWhitespace;
+Node.prototype.nodeTypeName = nodeTypeName;
+Node.prototype.displayName = nodeDisplayName;
+Node.prototype.contentPreview = nodeContentPreview;
+Node.prototype.isAncestor = isAncestorNode;
+Node.prototype.isDescendant = isDescendantNode;
+Node.prototype.firstCommonAncestor = firstCommonNodeAncestor;
+Node.prototype.nextSiblingSkippingWhitespace = nextSiblingSkippingWhitespace;
+Node.prototype.previousSiblingSkippingWhitespace = previousSiblingSkippingWhitespace;
+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.trimLeadingWhitespace = function()
+{
+    return this.replace(/^[\s\xA0]+/g, "");
+}
+
+String.prototype.trimTrailingWhitespace = function()
+{
+    return this.replace(/[\s\xA0]+$/g, "");
+}
+
+String.prototype.trimWhitespace = function()
+{
+    return this.replace(/^[\s\xA0]+|[\s\xA0]+$/g, "");
+}
+
+String.prototype.trimURL = function(baseURLDomain)
+{
+    var result = this.replace(new RegExp("^http[s]?:\/\/", "i"), "");
+    if (baseURLDomain)
+        result = result.replace(new RegExp("^" + baseURLDomain.escapeForRegExp(), "i"), "");
+    return result;
+}
+
+function getStyleTextWithShorthands(style)
+{
+    var cssText = "";
+    var foundProperties = {};
+    for (var i = 0; i < style.length; ++i) {
+        var individualProperty = style[i];
+        var shorthandProperty = style.getPropertyShorthand(individualProperty);
+        var propertyName = (shorthandProperty || individualProperty);
+
+        if (propertyName in foundProperties)
+            continue;
+
+        if (shorthandProperty) {
+            var value = getShorthandValue(style, shorthandProperty);
+            var priority = getShorthandPriority(style, shorthandProperty);
+        } else {
+            var value = style.getPropertyValue(individualProperty);
+            var priority = style.getPropertyPriority(individualProperty);
+        }
+
+        foundProperties[propertyName] = true;
+
+        cssText += propertyName + ": " + value;
+        if (priority)
+            cssText += " !" + priority;
+        cssText += "; ";
+    }
+
+    return cssText;
+}
+
+function getShorthandValue(style, shorthandProperty)
+{
+    var value = style.getPropertyValue(shorthandProperty);
+    if (!value) {
+        // Some shorthands (like border) return a null value, so compute a shorthand value.
+        // FIXME: remove this when http://bugs.webkit.org/show_bug.cgi?id=15823 is fixed.
+
+        var foundProperties = {};
+        for (var i = 0; i < style.length; ++i) {
+            var individualProperty = style[i];
+            if (individualProperty in foundProperties || style.getPropertyShorthand(individualProperty) !== shorthandProperty)
+                continue;
+
+            var individualValue = style.getPropertyValue(individualProperty);
+            if (style.isPropertyImplicit(individualProperty) || individualValue === "initial")
+                continue;
+
+            foundProperties[individualProperty] = true;
+
+            if (!value)
+                value = "";
+            else if (value.length)
+                value += " ";
+            value += individualValue;
+        }
+    }
+    return value;
+}
+
+function getShorthandPriority(style, shorthandProperty)
+{
+    var priority = style.getPropertyPriority(shorthandProperty);
+    if (!priority) {
+        for (var i = 0; i < style.length; ++i) {
+            var individualProperty = style[i];
+            if (style.getPropertyShorthand(individualProperty) !== shorthandProperty)
+                continue;
+            priority = style.getPropertyPriority(individualProperty);
+            break;
+        }
+    }
+    return priority;
+}
+
+function getLonghandProperties(style, shorthandProperty)
+{
+    var properties = [];
+    var foundProperties = {};
+
+    for (var i = 0; i < style.length; ++i) {
+        var individualProperty = style[i];
+        if (individualProperty in foundProperties || style.getPropertyShorthand(individualProperty) !== shorthandProperty)
+            continue;
+        foundProperties[individualProperty] = true;
+        properties.push(individualProperty);
+    }
+
+    return properties;
+}
+
+function getUniqueStyleProperties(style)
+{
+    var properties = [];
+    var foundProperties = {};
+
+    for (var i = 0; i < style.length; ++i) {
+        var property = style[i];
+        if (property in foundProperties)
+            continue;
+        foundProperties[property] = true;
+        properties.push(property);
+    }
+
+    return properties;
+}
+
+function isNodeWhitespace()
+{
+    if (!this || this.nodeType !== Node.TEXT_NODE)
+        return false;
+    if (!this.nodeValue.length)
+        return true;
+    return this.nodeValue.match(/^[\s\xA0]+$/);
+}
+
+function nodeTypeName()
+{
+    if (!this)
+        return "(unknown)";
+
+    switch (this.nodeType) {
+        case Node.ELEMENT_NODE: return "Element";
+        case Node.ATTRIBUTE_NODE: return "Attribute";
+        case Node.TEXT_NODE: return "Text";
+        case Node.CDATA_SECTION_NODE: return "Character Data";
+        case Node.ENTITY_REFERENCE_NODE: return "Entity Reference";
+        case Node.ENTITY_NODE: return "Entity";
+        case Node.PROCESSING_INSTRUCTION_NODE: return "Processing Instruction";
+        case Node.COMMENT_NODE: return "Comment";
+        case Node.DOCUMENT_NODE: return "Document";
+        case Node.DOCUMENT_TYPE_NODE: return "Document Type";
+        case Node.DOCUMENT_FRAGMENT_NODE: return "Document Fragment";
+        case Node.NOTATION_NODE: return "Notation";
+    }
+
+    return "(unknown)";
+}
+
+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 nodeContentPreview()
+{
+    if (!this || !this.hasChildNodes || !this.hasChildNodes())
+        return "";
+
+    var limit = 0;
+    var preview = "";
+
+    // always skip whitespace here
+    var currentNode = traverseNextNode.call(this, true, this);
+    while (currentNode) {
+        if (currentNode.nodeType === Node.TEXT_NODE)
+            preview += currentNode.nodeValue.escapeHTML();
+        else
+            preview += nodeDisplayName.call(currentNode).escapeHTML();
+
+        currentNode = traverseNextNode.call(currentNode, true, this);
+
+        if (++limit > 4) {
+            preview += "&#x2026;"; // ellipsis
+            break;
+        }
+    }
+
+    return preview.collapseWhitespace();
+}
+
+function objectsAreSame(a, b)
+{
+    // FIXME: Make this more generic so is works with any wrapped object, not just nodes.
+    // This function is used to compare nodes that might be JSInspectedObjectWrappers, since
+    // JavaScript equality is not true for JSInspectedObjectWrappers of the same node wrapped
+    // with different global ExecStates, we use isSameNode to compare them.
+    if (a === b)
+        return true;
+    if (!a || !b)
+        return false;
+    if (a.isSameNode && b.isSameNode)
+        return a.isSameNode(b);
+    return false;
+}
+
+function isAncestorNode(ancestor)
+{
+    if (!this || !ancestor)
+        return false;
+
+    var currentNode = ancestor.parentNode;
+    while (currentNode) {
+        if (objectsAreSame(this, currentNode))
+            return true;
+        currentNode = currentNode.parentNode;
+    }
+
+    return false;
+}
+
+function isDescendantNode(descendant)
+{
+    return isAncestorNode.call(descendant, this);
+}
+
+function firstCommonNodeAncestor(node)
+{
+    if (!this || !node)
+        return;
+
+    var node1 = this.parentNode;
+    var node2 = node.parentNode;
+
+    if ((!node1 || !node2) || !objectsAreSame(node1, node2))
+        return null;
+
+    while (node1 && node2) {
+        if (!node1.parentNode || !node2.parentNode)
+            break;
+        if (!objectsAreSame(node1, node2))
+            break;
+
+        node1 = node1.parentNode;
+        node2 = node2.parentNode;
+    }
+
+    return node1;
+}
+
+function nextSiblingSkippingWhitespace()
+{
+    if (!this)
+        return;
+    var node = this.nextSibling;
+    while (node && node.nodeType === Node.TEXT_NODE && isNodeWhitespace.call(node))
+        node = node.nextSibling;
+    return node;
+}
+
+function previousSiblingSkippingWhitespace()
+{
+    if (!this)
+        return;
+    var node = this.previousSibling;
+    while (node && node.nodeType === Node.TEXT_NODE && isNodeWhitespace.call(node))
+        node = node.previousSibling;
+    return node;
+}
+
+function firstChildSkippingWhitespace()
+{
+    if (!this)
+        return;
+    var node = this.firstChild;
+    while (node && node.nodeType === Node.TEXT_NODE && isNodeWhitespace.call(node))
+        node = nextSiblingSkippingWhitespace.call(node);
+    return node;
+}
+
+function lastChildSkippingWhitespace()
+{
+    if (!this)
+        return;
+    var node = this.lastChild;
+    while (node && node.nodeType === Node.TEXT_NODE && isNodeWhitespace.call(node))
+        node = previousSiblingSkippingWhitespace.call(node);
+    return node;
+}
+
+function traverseNextNode(skipWhitespace, stayWithin)
+{
+    if (!this)
+        return;
+
+    var node = skipWhitespace ? firstChildSkippingWhitespace.call(this) : this.firstChild;
+    if (node)
+        return node;
+
+    if (stayWithin && objectsAreSame(this, stayWithin))
+        return null;
+
+    node = skipWhitespace ? nextSiblingSkippingWhitespace.call(this) : this.nextSibling;
+    if (node)
+        return node;
+
+    node = this;
+    while (node && !(skipWhitespace ? nextSiblingSkippingWhitespace.call(node) : node.nextSibling) && (!stayWithin || !node.parentNode || !objectsAreSame(node.parentNode, stayWithin)))
+        node = node.parentNode;
+    if (!node)
+        return null;
+
+    return skipWhitespace ? nextSiblingSkippingWhitespace.call(node) : node.nextSibling;
+}
+
+function traversePreviousNode(skipWhitespace, stayWithin)
+{
+    if (!this)
+        return;
+    if (stayWithin && objectsAreSame(this, stayWithin))
+        return null;
+    var node = skipWhitespace ? previousSiblingSkippingWhitespace.call(this) : this.previousSibling;
+    while (node && (skipWhitespace ? lastChildSkippingWhitespace.call(node) : node.lastChild) )
+        node = skipWhitespace ? lastChildSkippingWhitespace.call(node) : node.lastChild;
+    if (node)
+        return node;
+    return this.parentNode;
+}
+
+function onlyTextChild(ignoreWhitespace)
+{
+    if (!this)
+        return null;
+
+    var firstChild = ignoreWhitespace ? firstChildSkippingWhitespace.call(this) : this.firstChild;
+    if (!firstChild || firstChild.nodeType !== Node.TEXT_NODE)
+        return null;
+
+    var sibling = ignoreWhitespace ? nextSiblingSkippingWhitespace.call(firstChild) : firstChild.nextSibling;
+    return sibling ? null : firstChild;
+}
+
+function nodeTitleInfo(hasChildren, linkify)
+{
+    var info = {title: "", hasChildren: hasChildren};
+
+    switch (this.nodeType) {
+        case Node.DOCUMENT_NODE:
+            info.title = "Document";
+            break;
+
+        case Node.ELEMENT_NODE:
+            info.title = "<span class=\"webkit-html-tag\">&lt;" + this.nodeName.toLowerCase().escapeHTML();
+
+            if (this.hasAttributes()) {
+                for (var i = 0; i < this.attributes.length; ++i) {
+                    var attr = this.attributes[i];
+                    info.title += " <span class=\"webkit-html-attribute\"><span class=\"webkit-html-attribute-name\">" + attr.name.escapeHTML() + "</span>=&#8203;\"";
+
+                    var value = attr.value;
+                    if (linkify && (attr.name === "src" || attr.name === "href")) {
+                        var value = value.replace(/([\/;:\)\]\}])/g, "$1\u200B");
+                        info.title += linkify(attr.value, value, "webkit-html-attribute-value", this.nodeName.toLowerCase() == "a");
+                    } else {
+                        var value = value.escapeHTML();
+                        value = value.replace(/([\/;:\)\]\}])/g, "$1&#8203;");
+                        info.title += "<span class=\"webkit-html-attribute-value\">" + value + "</span>";
+                    }
+                    info.title += "\"</span>";
+                }
+            }
+            info.title += "&gt;</span>&#8203;";
+
+            // If this element only has a single child that is a text node,
+            // just show that text and the closing tag inline rather than
+            // create a subtree for them
+
+            var textChild = onlyTextChild.call(this, Preferences.ignoreWhitespace);
+            var showInlineText = textChild && textChild.textContent.length < Preferences.maxInlineTextChildLength;
+
+            if (showInlineText) {
+                info.title += "<span class=\"webkit-html-text-node\">" + textChild.nodeValue.escapeHTML() + "</span>&#8203;<span class=\"webkit-html-tag\">&lt;/" + this.nodeName.toLowerCase().escapeHTML() + "&gt;</span>";
+                info.hasChildren = false;
+            }
+            break;
+
+        case Node.TEXT_NODE:
+            if (isNodeWhitespace.call(this))
+                info.title = "(whitespace)";
+            else
+                info.title = "\"<span class=\"webkit-html-text-node\">" + this.nodeValue.escapeHTML() + "</span>\"";
+            break
+
+        case Node.COMMENT_NODE:
+            info.title = "<span class=\"webkit-html-comment\">&lt;!--" + this.nodeValue.escapeHTML() + "--&gt;</span>";
+            break;
+
+        case Node.DOCUMENT_TYPE_NODE:
+            info.title = "<span class=\"webkit-html-doctype\">&lt;!DOCTYPE " + this.nodeName;
+            if (this.publicId) {
+                info.title += " PUBLIC \"" + this.publicId + "\"";
+                if (this.systemId)
+                    info.title += " \"" + this.systemId + "\"";
+            } else if (this.systemId)
+                info.title += " SYSTEM \"" + this.systemId + "\"";
+            if (this.internalSubset)
+                info.title += " [" + this.internalSubset + "]";
+            info.title += "&gt;</span>";
+            break;
+        default:
+            info.title = this.nodeName.toLowerCase().collapseWhitespace().escapeHTML();
+    }
+
+    return info;
+}
+
+function getDocumentForNode(node) {
+    return node.nodeType == Node.DOCUMENT_NODE ? node : node.ownerDocument;
+}
+
+function parentNodeOrFrameElement(node) {
+    var parent = node.parentNode;
+    if (parent)
+        return parent;
+
+    return getDocumentForNode(node).defaultView.frameElement;
+}
+
+function isAncestorIncludingParentFrames(a, b) {
+    if (objectsAreSame(a, b))
+        return false;
+    for (var node = b; node; node = getDocumentForNode(node).defaultView.frameElement)
+        if (objectsAreSame(a, node) || isAncestorNode.call(a, node))
+            return true;
+    return false;
+}
+
+Number.secondsToString = function(seconds, formatterFunction, higherResolution)
+{
+    if (!formatterFunction)
+        formatterFunction = String.sprintf;
+
+    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)
+{
+    if (!formatterFunction)
+        formatterFunction = String.sprintf;
+
+    if (bytes < 1024)
+        return formatterFunction("%.0fB", bytes);
+
+    var kilobytes = bytes / 1024;
+    if (kilobytes < 1024)
+        return formatterFunction("%.2fKB", kilobytes);
+
+    var megabytes = kilobytes / 1024;
+    return formatterFunction("%.3fMB", 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);
+    }
+}
+
+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)
+    {
+        substitution = parseInt(substitution);
+        return !isNaN(substitution) ? substitution : 0;
+    },
+
+    f: function(substitution, token)
+    {
+        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)
+    {
+        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 };
+}
diff --git a/themes/default.dll b/themes/default.dll
new file mode 100644
index 0000000..023dfcf
--- /dev/null
+++ b/themes/default.dll
Binary files differ
diff --git a/wow_helper.exe b/wow_helper.exe
new file mode 100644
index 0000000..f9bfb4b
--- /dev/null
+++ b/wow_helper.exe
Binary files differ