[SCM] WebKit Debian packaging branch, webkit-1.2, updated. upstream/1.1.90-6072-g9a69373

yurys at chromium.org yurys at chromium.org
Thu Apr 8 01:42:48 UTC 2010


The following commit has been merged in the webkit-1.2 branch:
commit 858f2f12494dabcee78df2c7838adfb676b542c8
Author: yurys at chromium.org <yurys at chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Tue Feb 9 15:15:08 2010 +0000

    2010-02-09  Yury Semikhatsky  <yurys at chromium.org>
    
            Reviewed by Pavel Feldman.
    
            Upstream JavaScript part of DevTools WebKit API implementation(now
            with the added files).
    
            https://bugs.webkit.org/show_bug.cgi?id=34744
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@54547 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebKit/chromium/ChangeLog b/WebKit/chromium/ChangeLog
index de55a46..b5697c2 100644
--- a/WebKit/chromium/ChangeLog
+++ b/WebKit/chromium/ChangeLog
@@ -2,6 +2,385 @@
 
         Reviewed by Pavel Feldman.
 
+        Upstream JavaScript part of DevTools WebKit API implementation(now
+        with the added files).
+
+        https://bugs.webkit.org/show_bug.cgi?id=34744
+
+        * WebKit.gypi: Added.
+        * src/js/DebuggerAgent.js: Added.
+        (devtools.DebuggerAgent):
+        (devtools.DebuggerAgent.prototype.reset):
+        (devtools.DebuggerAgent.prototype.initUI):
+        (devtools.DebuggerAgent.prototype.resolveScriptSource.this.requestSeqToCallback_.cmd.getSequenceNumber):
+        (devtools.DebuggerAgent.prototype.resolveScriptSource):
+        (devtools.DebuggerAgent.prototype.pauseExecution):
+        (devtools.DebuggerAgent.prototype.addBreakpoint):
+        (devtools.DebuggerAgent.prototype.removeBreakpoint):
+        (devtools.DebuggerAgent.prototype.updateBreakpoint):
+        (devtools.DebuggerAgent.prototype.stepIntoStatement):
+        (devtools.DebuggerAgent.prototype.stepOutOfFunction):
+        (devtools.DebuggerAgent.prototype.stepOverStatement):
+        (devtools.DebuggerAgent.prototype.resumeExecution):
+        (devtools.DebuggerAgent.prototype.createExceptionMessage_):
+        (devtools.DebuggerAgent.prototype.showPendingExceptionMessage_):
+        (devtools.DebuggerAgent.prototype.clearExceptionMessage_):
+        (devtools.DebuggerAgent.prototype.pauseOnExceptions):
+        (devtools.DebuggerAgent.prototype.setPauseOnExceptions):
+        (devtools.DebuggerAgent.prototype.requestEvaluate):
+        (devtools.DebuggerAgent.prototype.resolveChildren):
+        (devtools.DebuggerAgent.prototype.resolveScope.this.requestSeqToCallback_.cmd.getSequenceNumber):
+        (devtools.DebuggerAgent.prototype.resolveScope):
+        (devtools.DebuggerAgent.prototype.resolveFrameVariables_.scopeResponseHandler):
+        (devtools.DebuggerAgent.prototype.resolveFrameVariables_):
+        (devtools.DebuggerAgent.prototype.resolveCompletionsOnFrame):
+        (devtools.DebuggerAgent.prototype.getScriptContextType):
+        (devtools.DebuggerAgent.prototype.requestClearBreakpoint_):
+        (devtools.DebuggerAgent.prototype.requestChangeBreakpoint_):
+        (devtools.DebuggerAgent.prototype.requestBacktrace_):
+        (devtools.DebuggerAgent.sendCommand_):
+        (devtools.DebuggerAgent.prototype.stepCommand_):
+        (devtools.DebuggerAgent.prototype.requestLookup_):
+        (devtools.DebuggerAgent.prototype.setContextId_.this.requestSeqToCallback_.cmd.getSequenceNumber):
+        (devtools.DebuggerAgent.prototype.setContextId_):
+        (devtools.DebuggerAgent.prototype.handleDebuggerOutput_):
+        (devtools.DebuggerAgent.prototype.handleBreakEvent_):
+        (devtools.DebuggerAgent.prototype.handleExceptionEvent_):
+        (devtools.DebuggerAgent.prototype.handleScriptsResponse_):
+        (devtools.DebuggerAgent.prototype.isScriptFromInspectedContext_):
+        (devtools.DebuggerAgent.prototype.handleSetBreakpointResponse_):
+        (devtools.DebuggerAgent.prototype.handleAfterCompileEvent_):
+        (devtools.DebuggerAgent.prototype.addScriptInfo_):
+        (devtools.DebuggerAgent.prototype.handleClearBreakpointResponse_):
+        (devtools.DebuggerAgent.prototype.handleBacktraceResponse_):
+        (devtools.DebuggerAgent.prototype.doHandleBacktraceResponse_):
+        (devtools.DebuggerAgent.prototype.evaluateInCallFrame):
+        (devtools.DebuggerAgent.prototype.invokeCallbackForResponse_):
+        (devtools.DebuggerAgent.prototype.formatCallFrame_):
+        (devtools.DebuggerAgent.formatObjectProperties_):
+        (devtools.DebuggerAgent.propertiesToProxies_):
+        (devtools.DebuggerAgent.formatObjectProxy_):
+        (devtools.DebuggerAgent.webkitToV8LineNumber_):
+        (devtools.DebuggerAgent.v8ToWwebkitLineNumber_):
+        (devtools.ScriptInfo):
+        (devtools.ScriptInfo.prototype.getLineOffset):
+        (devtools.ScriptInfo.prototype.getContextType):
+        (devtools.ScriptInfo.prototype.getUrl):
+        (devtools.ScriptInfo.prototype.isUnresolved):
+        (devtools.ScriptInfo.prototype.getBreakpointInfo):
+        (devtools.ScriptInfo.prototype.addBreakpointInfo):
+        (devtools.ScriptInfo.prototype.removeBreakpointInfo):
+        (devtools.BreakpointInfo):
+        (devtools.BreakpointInfo.prototype.getLine):
+        (devtools.BreakpointInfo.prototype.getV8Id):
+        (devtools.BreakpointInfo.prototype.setV8Id):
+        (devtools.BreakpointInfo.prototype.markAsRemoved):
+        (devtools.BreakpointInfo.prototype.isRemoved):
+        (devtools.CallFrame):
+        (devtools.CallFrame.prototype.evaluate_):
+        (devtools.DebugCommand):
+        (devtools.DebugCommand.prototype.getSequenceNumber):
+        (devtools.DebugCommand.prototype.toJSONProtocol):
+        (devtools.DebuggerMessage):
+        (devtools.DebuggerMessage.prototype.getType):
+        (devtools.DebuggerMessage.prototype.getEvent):
+        (devtools.DebuggerMessage.prototype.getCommand):
+        (devtools.DebuggerMessage.prototype.getRequestSeq):
+        (devtools.DebuggerMessage.prototype.isRunning):
+        (devtools.DebuggerMessage.prototype.isSuccess):
+        (devtools.DebuggerMessage.prototype.getMessage):
+        (devtools.DebuggerMessage.prototype.getBody):
+        (devtools.DebuggerMessage.prototype.lookup):
+        * src/js/DevTools.js: Added.
+        (devtools.dispatch):
+        (devtools.ToolsAgent):
+        (devtools.ToolsAgent.prototype.reset):
+        (devtools.ToolsAgent.prototype.evaluateJavaScript):
+        (devtools.ToolsAgent.prototype.getDebuggerAgent):
+        (devtools.ToolsAgent.prototype.getProfilerAgent):
+        (devtools.ToolsAgent.prototype.frameNavigate_):
+        (devtools.ToolsAgent.prototype.dispatchOnClient_):
+        (devtools.ToolsAgent.prototype.evaluate):
+        (WebInspector.setResourcesPanelEnabled):
+        (debugPrint):
+        (devtools):
+        (WebInspector.loaded):
+        ():
+        (WebInspector.ScriptView.prototype.setupSourceFrameIfNeeded):
+        (WebInspector.ScriptView.prototype.didResolveScriptSource_):
+        (WebInspector.UnresolvedPropertyValue):
+        (WebInspector.UIString):
+        (WebInspector.resourceTrackingWasEnabled):
+        (WebInspector.resourceTrackingWasDisabled):
+        (WebInspector.TestController.prototype.runAfterPendingDispatches):
+        (WebInspector.queuesAreEmpty):
+        (WebInspector.pausedScript):
+        * src/js/DevToolsHostStub.js: Added.
+        (.RemoteDebuggerAgentStub):
+        (.RemoteDebuggerAgentStub.prototype.getContextId):
+        (.RemoteProfilerAgentStub):
+        (.RemoteProfilerAgentStub.prototype.getActiveProfilerModules):
+        (.RemoteProfilerAgentStub.prototype.getLogLines):
+        (.RemoteToolsAgentStub):
+        (.RemoteToolsAgentStub.prototype.dispatchOnInjectedScript):
+        (.RemoteToolsAgentStub.prototype.dispatchOnInspectorController):
+        (.RemoteToolsAgentStub.prototype.executeVoidJavaScript):
+        (.ProfilerStubHelper):
+        (.ProfilerStubHelper.GetInstance):
+        (.ProfilerStubHelper.prototype.StopProfiling):
+        (.ProfilerStubHelper.prototype.StartProfiling):
+        (.ProfilerStubHelper.prototype.getActiveProfilerModules):
+        (.ProfilerStubHelper.prototype.getLogLines):
+        (.RemoteDebuggerCommandExecutorStub):
+        (.RemoteDebuggerCommandExecutorStub.prototype.DebuggerCommand):
+        (.RemoteDebuggerCommandExecutorStub.prototype.DebuggerPauseScript):
+        (.RemoteDebuggerCommandExecutorStub.prototype.sendResponse_):
+        (.DevToolsHostStub):
+        (.DevToolsHostStub.prototype.reset):
+        (.DevToolsHostStub.prototype.setting):
+        (.DevToolsHostStub.prototype.setSetting):
+        * src/js/HeapProfilerPanel.js: Added.
+        (WebInspector.ProfilesPanel.prototype.addSnapshot):
+        (WebInspector.HeapSnapshotView):
+        (WebInspector.HeapSnapshotView.prototype.get statusBarItems):
+        (WebInspector.HeapSnapshotView.prototype.get profile):
+        (WebInspector.HeapSnapshotView.prototype.set profile):
+        (WebInspector.HeapSnapshotView.prototype.show):
+        (WebInspector.HeapSnapshotView.prototype.hide):
+        (WebInspector.HeapSnapshotView.prototype.resize):
+        (WebInspector.HeapSnapshotView.prototype.refresh):
+        (WebInspector.HeapSnapshotView.prototype.refreshShowAsPercents):
+        (WebInspector.HeapSnapshotView.prototype._deleteSearchMatchedFlags):
+        (WebInspector.HeapSnapshotView.prototype.searchCanceled):
+        (WebInspector.HeapSnapshotView.prototype.performSearch):
+        (WebInspector.HeapSnapshotView.prototype.jumpToFirstSearchResult.WebInspector.CPUProfileView.prototype.jumpToFirstSearchResult.jumpToLastSearchResult.WebInspector.CPUProfileView.prototype.jumpToLastSearchResult.jumpToNextSearchResult.WebInspector.CPUProfileView.prototype.jumpToNextSearchResult.jumpToPreviousSearchResult.WebInspector.CPUProfileView.prototype.jumpToPreviousSearchResult.showingFirstSearchResult.WebInspector.CPUProfileView.prototype.showingFirstSearchResult.showingLastSearchResult.WebInspector.CPUProfileView.prototype.showingLastSearchResult._jumpToSearchResult.WebInspector.CPUProfileView.prototype._jumpToSearchResult.refreshVisibleData):
+        (WebInspector.HeapSnapshotView.prototype._changeBase):
+        (WebInspector.HeapSnapshotView.prototype._createSnapshotDataGridList):
+        (WebInspector.HeapSnapshotView.prototype._mouseDownInDataGrid):
+        (WebInspector.HeapSnapshotView.prototype.get _isShowingAsPercent):
+        (WebInspector.HeapSnapshotView.prototype._percentClicked):
+        (WebInspector.HeapSnapshotView.prototype._resetDataGridList):
+        (WebInspector.HeapSnapshotView.prototype._sortData):
+        (WebInspector.HeapSnapshotView.prototype._updateBaseOptions):
+        (WebInspector.HeapSnapshotView.prototype._updatePercentButton):
+        (WebInspector.HeapSnapshotView.prototype._updateSummaryGraph):
+        (WebInspector.HeapSnapshotView.SearchHelper.operations.LESS):
+        (WebInspector.HeapSnapshotView.SearchHelper.operations.LESS_OR_EQUAL):
+        (WebInspector.HeapSnapshotView.SearchHelper.operations.EQUAL):
+        (WebInspector.HeapSnapshotView.SearchHelper.operations.GREATER_OR_EQUAL):
+        (WebInspector.HeapSnapshotView.SearchHelper.operations.GREATER):
+        (WebInspector.HeapSnapshotView.SearchHelper.parseOperationAndNumber):
+        (WebInspector.HeapSummaryCalculator):
+        (WebInspector.HeapSummaryCalculator.prototype.computeSummaryValues):
+        (WebInspector.HeapSummaryCalculator.prototype.formatValue):
+        (WebInspector.HeapSummaryCalculator.prototype.get showAsPercent):
+        (WebInspector.HeapSummaryCalculator.prototype.set showAsPercent):
+        (WebInspector.HeapSummaryCountCalculator):
+        (WebInspector.HeapSummaryCountCalculator.prototype._highFromLow):
+        (WebInspector.HeapSummaryCountCalculator.prototype._valueToString):
+        (WebInspector.HeapSummarySizeCalculator):
+        (WebInspector.HeapSummarySizeCalculator.prototype._highFromLow):
+        (WebInspector.HeapSnapshotSidebarTreeElement):
+        (WebInspector.HeapSnapshotSidebarTreeElement.prototype.get mainTitle):
+        (WebInspector.HeapSnapshotSidebarTreeElement.prototype.set mainTitle):
+        (WebInspector.HeapSnapshotDataGridNodeWithRetainers):
+        (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.get _hasRetainers):
+        (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.get _parent):
+        (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype._populate.if):
+        (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype._populate):
+        (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.produceDiff):
+        (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.sort):
+        (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.signForDelta):
+        (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.showDeltaAsPercent):
+        (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.getTotalCount):
+        (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.getTotalSize):
+        (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.get countPercent):
+        (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.get sizePercent):
+        (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.get countDeltaPercent):
+        (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.get sizeDeltaPercent):
+        (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.get data):
+        (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.createCell):
+        (WebInspector.HeapSnapshotDataGridNode):
+        (WebInspector.HeapSnapshotDataGridList):
+        (WebInspector.HeapSnapshotDataGridList.prototype.appendChild):
+        (WebInspector.HeapSnapshotDataGridList.prototype.insertChild):
+        (WebInspector.HeapSnapshotDataGridList.prototype.removeChildren):
+        (WebInspector.HeapSnapshotDataGridList.prototype.populateChildren):
+        (WebInspector.HeapSnapshotDataGridList.propertyComparator.comparator):
+        (WebInspector.HeapSnapshotDataGridList.propertyComparator):
+        (WebInspector.HeapSnapshotDataGridRetainerNode):
+        (WebInspector.HeapSnapshotDataGridRetainerNode.prototype.get sizePercent):
+        (WebInspector.HeapSnapshotDataGridRetainerNode.prototype.get sizeDeltaPercent):
+        (WebInspector.HeapSnapshotDataGridRetainerNode.prototype._calculateRetainers):
+        (WebInspector.HeapSnapshotProfileType):
+        (WebInspector.HeapSnapshotProfileType.prototype.get buttonTooltip):
+        (WebInspector.HeapSnapshotProfileType.prototype.get buttonStyle):
+        (WebInspector.HeapSnapshotProfileType.prototype.buttonClicked):
+        (WebInspector.HeapSnapshotProfileType.prototype.get welcomeMessage):
+        (WebInspector.HeapSnapshotProfileType.prototype.createSidebarTreeElementForProfile):
+        (WebInspector.HeapSnapshotProfileType.prototype.createView):
+        ():
+        * src/js/InjectDispatch.js: Added.
+        (InspectorControllerDispatcher.dispatch):
+        (ApuAgentDispatcher.dispatchToApu):
+        (dispatch):
+        (devtools):
+        * src/js/InspectorControllerImpl.js: Added.
+        (devtools.InspectorBackendImpl):
+        (devtools.InspectorBackendImpl.prototype.toggleNodeSearch):
+        (devtools.InspectorBackendImpl.prototype.debuggerEnabled):
+        (devtools.InspectorBackendImpl.prototype.profilerEnabled):
+        (devtools.InspectorBackendImpl.prototype.addBreakpoint):
+        (devtools.InspectorBackendImpl.prototype.removeBreakpoint):
+        (devtools.InspectorBackendImpl.prototype.updateBreakpoint):
+        (devtools.InspectorBackendImpl.prototype.pauseInDebugger):
+        (devtools.InspectorBackendImpl.prototype.resumeDebugger):
+        (devtools.InspectorBackendImpl.prototype.stepIntoStatementInDebugger):
+        (devtools.InspectorBackendImpl.prototype.stepOutOfFunctionInDebugger):
+        (devtools.InspectorBackendImpl.prototype.stepOverStatementInDebugger):
+        (devtools.InspectorBackendImpl.prototype.setPauseOnExceptionsState):
+        (devtools.InspectorBackendImpl.prototype.pauseOnExceptionsState):
+        (devtools.InspectorBackendImpl.prototype.pauseOnExceptions):
+        (devtools.InspectorBackendImpl.prototype.setPauseOnExceptions):
+        (devtools.InspectorBackendImpl.prototype.startProfiling):
+        (devtools.InspectorBackendImpl.prototype.stopProfiling):
+        (devtools.InspectorBackendImpl.prototype.getProfileHeaders):
+        (devtools.InspectorBackendImpl.prototype.addFullProfile):
+        (devtools.InspectorBackendImpl.prototype.getProfile):
+        (devtools.InspectorBackendImpl.prototype.takeHeapSnapshot):
+        (devtools.InspectorBackendImpl.prototype.dispatchOnInjectedScript):
+        (devtools.InspectorBackendImpl.prototype.installInspectorControllerDelegate_):
+        (devtools.InspectorBackendImpl.prototype.callInspectorController_):
+        * src/js/ProfilerAgent.js: Added.
+        (devtools.ProfilerAgent):
+        (devtools.ProfilerAgent.prototype.setupProfilerProcessorCallbacks):
+        (devtools.ProfilerAgent.prototype.initializeProfiling):
+        (devtools.ProfilerAgent.prototype.startProfiling):
+        (devtools.ProfilerAgent.prototype.stopProfiling):
+        (devtools.ProfilerAgent.prototype.didGetActiveProfilerModules_):
+        (devtools.ProfilerAgent.prototype.didGetLogLines_):
+        * src/js/ProfilerProcessor.js: Added.
+        (devtools.profiler.WebKitViewBuilder):
+        (devtools.profiler.WebKitViewBuilder.prototype.createViewNode):
+        (devtools.profiler.WebKitViewNode):
+        (set get devtools.profiler.WebKitViewNode.prototype.initFuncInfo_):
+        (devtools.profiler.JsProfile):
+        (devtools.profiler.JsProfile.prototype.skipThisFunction):
+        (devtools.profiler.Processor):
+        (devtools.profiler.Processor.prototype.printError):
+        (devtools.profiler.Processor.prototype.skipDispatch):
+        (devtools.profiler.Processor.prototype.setCallbacks):
+        (devtools.profiler.Processor.prototype.setNewProfileCallback):
+        (devtools.profiler.Processor.prototype.processProfiler_.switch.break):
+        (devtools.profiler.Processor.prototype.processProfiler_):
+        (devtools.profiler.Processor.prototype.processCodeCreation_):
+        (devtools.profiler.Processor.prototype.processCodeMove_):
+        (devtools.profiler.Processor.prototype.processCodeDelete_):
+        (devtools.profiler.Processor.prototype.processFunctionCreation_):
+        (devtools.profiler.Processor.prototype.processFunctionMove_):
+        (devtools.profiler.Processor.prototype.processFunctionDelete_):
+        (devtools.profiler.Processor.prototype.processTick_):
+        (devtools.profiler.Processor.prototype.processTickV2_):
+        (devtools.profiler.Processor.prototype.processHeapSampleBegin_):
+        (devtools.profiler.Processor.prototype.processHeapSampleStats_):
+        (devtools.profiler.Processor.prototype.processHeapSampleItem_):
+        (devtools.profiler.Processor.prototype.processHeapJsConsItem_):
+        (devtools.profiler.Processor.prototype.processHeapJsRetItem_.mergeRetainers):
+        (devtools.profiler.Processor.prototype.processHeapJsRetItem_):
+        (devtools.profiler.Processor.prototype.processHeapSampleEnd_):
+        (devtools.profiler.Processor.prototype.createProfileForView):
+        * src/js/Tests.js: Added.
+        (.TestSuite):
+        (.TestSuite.prototype.fail):
+        (.TestSuite.prototype.assertEquals):
+        (.TestSuite.prototype.assertTrue):
+        (.TestSuite.prototype.assertContains):
+        (.TestSuite.prototype.takeControl):
+        (.TestSuite.prototype.releaseControl):
+        (.TestSuite.prototype.reportOk_):
+        (.TestSuite.prototype.reportFailure_):
+        (.TestSuite.prototype.runTest):
+        (.TestSuite.prototype.showPanel):
+        (.TestSuite.prototype.addSniffer.receiver.methodName):
+        (.TestSuite.prototype.addSniffer):
+        (.TestSuite.prototype.testHostIsPresent):
+        (.TestSuite.prototype.testElementsTreeRoot):
+        (.TestSuite.prototype.testMainResource):
+        (.TestSuite.prototype.testResourceContentLength.this.addSniffer.):
+        (.TestSuite.prototype.testResourceHeaders):
+        (.TestSuite.prototype.testCachedResourceMimeType.this.addSniffer.):
+        (.TestSuite.prototype.testCachedResourceMimeType):
+        (.TestSuite.prototype.testProfilerTab):
+        (.TestSuite.prototype.testScriptsTabIsPopulatedOnInspectedPageRefresh.waitUntilScriptIsParsed):
+        (.TestSuite.prototype.testScriptsTabIsPopulatedOnInspectedPageRefresh.checkScriptsPanel):
+        (.TestSuite.prototype.testScriptsTabIsPopulatedOnInspectedPageRefresh):
+        (.TestSuite.prototype.testNoScriptDuplicatesOnPanelSwitch.switchToElementsTab):
+        (.TestSuite.prototype.testNoScriptDuplicatesOnPanelSwitch.switchToScriptsTab):
+        (.TestSuite.prototype.testNoScriptDuplicatesOnPanelSwitch.checkScriptsPanel):
+        (.TestSuite.prototype.testNoScriptDuplicatesOnPanelSwitch.checkNoDuplicates):
+        (.TestSuite.prototype.testPauseOnException):
+        (.TestSuite.prototype.testPauseWhenLoadingDevTools):
+        (.TestSuite.prototype.testPauseWhenScriptIsRunning.testScriptPauseAfterDelay):
+        (.TestSuite.prototype.testPauseWhenScriptIsRunning.testScriptPause):
+        (.TestSuite.prototype.testPauseWhenScriptIsRunning):
+        (.TestSuite.prototype.optionsToString_):
+        (.TestSuite.prototype.evaluateInConsole_):
+        (.TestSuite.prototype.waitForSetBreakpointResponse_):
+        (.TestSuite.prototype.testEvalOnCallFrame.setBreakpointCallback):
+        (.TestSuite.prototype.testEvalOnCallFrame.waitForBreakpointHit):
+        (.TestSuite.prototype.testCompletionOnPause):
+        (.TestSuite.prototype.testCompletionOnPause.testLocalsCompletion):
+        (.TestSuite.prototype.testCompletionOnPause.testThisCompletion):
+        (.TestSuite.prototype.testCompletionOnPause.testFieldCompletion):
+        (.TestSuite.prototype.testCompletionOnPause.checkCompletions):
+        (.TestSuite.prototype.testAutoContinueOnSyntaxError.checkScriptsList):
+        (.TestSuite.prototype.testAutoContinueOnSyntaxError.waitForExceptionEvent.test):
+        (.TestSuite.prototype.testAutoContinueOnSyntaxError.waitForExceptionEvent):
+        (.TestSuite.prototype._checkExecutionLine):
+        (.TestSuite.prototype._scriptsAreParsed):
+        (.TestSuite.prototype._waitForScriptPause):
+        (.TestSuite.prototype._checkSourceFrameWhenLoaded.checkExecLine):
+        (.TestSuite.prototype._checkSourceFrameWhenLoaded):
+        (.TestSuite.prototype._performSteps.doNextAction):
+        (.TestSuite.prototype._performSteps):
+        (.TestSuite.prototype._executeCodeWhenScriptsAreParsed.executeFunctionInInspectedPage):
+        (.TestSuite.prototype._waitUntilScriptsAreParsed.waitForAllScripts):
+        (.TestSuite.prototype._waitUntilScriptsAreParsed):
+        (.TestSuite.prototype._executeFunctionForStepTest):
+        (.TestSuite.prototype.testStepOver):
+        (.TestSuite.prototype.testStepOut):
+        (.TestSuite.prototype.testStepIn):
+        (.TestSuite.prototype._evaluateXpath):
+        (.TestSuite.prototype._findNode):
+        (.TestSuite.prototype._findText):
+        (.TestSuite.prototype._nodeIterator):
+        (.TestSuite.prototype._checkScopeSectionDiv):
+        (.TestSuite.prototype._expandScopeSections.updateListener):
+        (.TestSuite.prototype._expandScopeSections):
+        (.TestSuite.prototype.testExpandScope):
+        (.TestSuite.prototype.testExpandScope.examineScopes):
+        (.TestSuite.prototype._findChildProperty):
+        (.TestSuite.prototype._hookGetPropertiesCallback.accessor.getProperties):
+        (.TestSuite.prototype._hookGetPropertiesCallback.try):
+        (.TestSuite.prototype._hookGetPropertiesCallback):
+        (.TestSuite.prototype.testDebugIntrinsicProperties.expandLocalScope):
+        (.TestSuite.prototype.testDebugIntrinsicProperties):
+        (.TestSuite.prototype.testDebugIntrinsicProperties.expandAndCheckNextProperty):
+        (.TestSuite.prototype.testDebugIntrinsicProperties.checkProperty):
+        (.TestSuite.createKeyEvent):
+        (.TestSuite.prototype.testConsoleLog.assertNext):
+        (.TestSuite.prototype.testConsoleLog):
+        (.TestSuite.prototype.testEvalGlobal.initEval):
+        (.TestSuite.prototype.testEvalGlobal):
+        (.TestSuite.prototype.testShowStoragePanel.this.addSniffer.):
+        (.TestSuite.prototype.testShowStoragePanel.this.addSniffer):
+        (.uiTests.runAllTests):
+        (.uiTests.runTest):
+
+2010-02-09  Yury Semikhatsky  <yurys at chromium.org>
+
+        Reviewed by Pavel Feldman.
+
         Upstream JavaScript part of DevTools WebKit API implementation
 
         https://bugs.webkit.org/show_bug.cgi?id=34744
diff --git a/WebKit/chromium/WebKit.gypi b/WebKit/chromium/WebKit.gypi
new file mode 100644
index 0000000..cf4dc93
--- /dev/null
+++ b/WebKit/chromium/WebKit.gypi
@@ -0,0 +1,52 @@
+#
+# Copyright (C) 2010 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#         * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#         * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#         * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+{
+    'variables': {
+        # List of DevTools source files, ordered by dependencies. It is used both
+        # for copying them to resource dir, and for generating 'devtools.html' file.
+        'devtools_js_files': [
+            'src/js/InspectorControllerImpl.js',
+            'src/js/DebuggerAgent.js',
+            'src/js/ProfilerAgent.js',
+            'src/js/ProfilerProcessor.js',
+            'src/js/HeapProfilerPanel.js',
+            'src/js/DevTools.js',
+            'src/js/DevToolsHostStub.js',
+            'src/js/Tests.js',
+        ],
+    },
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/WebKit/chromium/src/js/DebuggerAgent.js b/WebKit/chromium/src/js/DebuggerAgent.js
new file mode 100644
index 0000000..baf5ecb
--- /dev/null
+++ b/WebKit/chromium/src/js/DebuggerAgent.js
@@ -0,0 +1,1528 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @fileoverview Provides communication interface to remote v8 debugger. See
+ * protocol decription at http://code.google.com/p/v8/wiki/DebuggerProtocol
+ */
+
+/**
+ * FIXME: change field naming style to use trailing underscore.
+ * @constructor
+ */
+devtools.DebuggerAgent = function()
+{
+    RemoteDebuggerAgent.debuggerOutput = this.handleDebuggerOutput_.bind(this);
+    RemoteDebuggerAgent.setContextId = this.setContextId_.bind(this);
+
+    /**
+     * Id of the inspected page global context. It is used for filtering scripts.
+     * @type {number}
+     */
+    this.contextId_ = null;
+
+    /**
+     * Mapping from script id to script info.
+     * @type {Object}
+     */
+    this.parsedScripts_ = null;
+
+    /**
+     * Mapping from the request id to the devtools.BreakpointInfo for the
+     * breakpoints whose v8 ids are not set yet. These breakpoints are waiting for
+     * "setbreakpoint" responses to learn their ids in the v8 debugger.
+     * @see #handleSetBreakpointResponse_
+     * @type {Object}
+     */
+    this.requestNumberToBreakpointInfo_ = null;
+
+    /**
+     * Information on current stack frames.
+     * @type {Array.<devtools.CallFrame>}
+     */
+    this.callFrames_ = [];
+
+    /**
+     * Whether to stop in the debugger on the exceptions.
+     * @type {boolean}
+     */
+    this.pauseOnExceptions_ = false;
+
+    /**
+     * Mapping: request sequence number->callback.
+     * @type {Object}
+     */
+    this.requestSeqToCallback_ = null;
+
+    /**
+     * Whether the scripts panel has been shown and initialilzed.
+     * @type {boolean}
+     */
+    this.scriptsPanelInitialized_ = false;
+
+    /**
+     * Whether the scripts list should be requested next time when context id is
+     * set.
+     * @type {boolean}
+     */
+    this.requestScriptsWhenContextIdSet_ = false;
+
+    /**
+     * Whether the agent is waiting for initial scripts response.
+     * @type {boolean}
+     */
+    this.waitingForInitialScriptsResponse_ = false;
+
+    /**
+     * If backtrace response is received when initial scripts response
+     * is not yet processed the backtrace handling will be postponed until
+     * after the scripts response processing. The handler bound to its arguments
+     * and this agent will be stored in this field then.
+     * @type {?function()}
+     */
+    this.pendingBacktraceResponseHandler_ = null;
+
+    /**
+     * Container of all breakpoints set using resource URL. These breakpoints
+     * survive page reload. Breakpoints set by script id(for scripts that don't
+     * have URLs) are stored in ScriptInfo objects.
+     * @type {Object}
+     */
+    this.urlToBreakpoints_ = {};
+
+
+    /**
+     * Exception message that is shown to user while on exception break.
+     * @type {WebInspector.ConsoleMessage}
+     */
+    this.currentExceptionMessage_ = null;
+};
+
+
+/**
+ * A copy of the scope types from v8/src/mirror-delay.js
+ * @enum {number}
+ */
+devtools.DebuggerAgent.ScopeType = {
+    Global: 0,
+    Local: 1,
+    With: 2,
+    Closure: 3,
+    Catch: 4
+};
+
+
+/**
+ * Resets debugger agent to its initial state.
+ */
+devtools.DebuggerAgent.prototype.reset = function()
+{
+    this.contextId_ = null;
+    // No need to request scripts since they all will be pushed in AfterCompile
+    // events.
+    this.requestScriptsWhenContextIdSet_ = false;
+    this.waitingForInitialScriptsResponse_ = false;
+
+    this.parsedScripts_ = {};
+    this.requestNumberToBreakpointInfo_ = {};
+    this.callFrames_ = [];
+    this.requestSeqToCallback_ = {};
+};
+
+
+/**
+ * Initializes scripts UI. This method is called every time Scripts panel
+ * is shown. It will send request for context id if it's not set yet.
+ */
+devtools.DebuggerAgent.prototype.initUI = function()
+{
+    // Initialize scripts cache when Scripts panel is shown first time.
+    if (this.scriptsPanelInitialized_)
+        return;
+    this.scriptsPanelInitialized_ = true;
+    if (this.contextId_) {
+        // We already have context id. This means that we are here from the
+        // very beginning of the page load cycle and hence will get all scripts
+        // via after-compile events. No need to request scripts for this session.
+        //
+        // There can be a number of scripts from after-compile events that are
+        // pending addition into the UI.
+        for (var scriptId in this.parsedScripts_) {
+          var script = this.parsedScripts_[scriptId];
+          WebInspector.parsedScriptSource(scriptId, script.getUrl(), undefined /* script source */, script.getLineOffset());
+        }
+        return;
+    }
+    this.waitingForInitialScriptsResponse_ = true;
+    // Script list should be requested only when current context id is known.
+    RemoteDebuggerAgent.getContextId();
+    this.requestScriptsWhenContextIdSet_ = true;
+};
+
+
+/**
+ * Asynchronously requests the debugger for the script source.
+ * @param {number} scriptId Id of the script whose source should be resolved.
+ * @param {function(source:?string):void} callback Function that will be called
+ *     when the source resolution is completed. "source" parameter will be null
+ *     if the resolution fails.
+ */
+devtools.DebuggerAgent.prototype.resolveScriptSource = function(scriptId, callback)
+{
+    var script = this.parsedScripts_[scriptId];
+    if (!script || script.isUnresolved()) {
+        callback(null);
+        return;
+    }
+
+    var cmd = new devtools.DebugCommand("scripts", {
+        "ids": [scriptId],
+        "includeSource": true
+    });
+    devtools.DebuggerAgent.sendCommand_(cmd);
+    // Force v8 execution so that it gets to processing the requested command.
+    RemoteToolsAgent.executeVoidJavaScript();
+
+    this.requestSeqToCallback_[cmd.getSequenceNumber()] = function(msg) {
+        if (msg.isSuccess()) {
+            var scriptJson = msg.getBody()[0];
+            if (scriptJson)
+                callback(scriptJson.source);
+            else
+                callback(null);
+        } else
+            callback(null);
+    };
+};
+
+
+/**
+ * Tells the v8 debugger to stop on as soon as possible.
+ */
+devtools.DebuggerAgent.prototype.pauseExecution = function()
+{
+    RemoteDebuggerCommandExecutor.DebuggerPauseScript();
+};
+
+
+/**
+ * @param {number} sourceId Id of the script fot the breakpoint.
+ * @param {number} line Number of the line for the breakpoint.
+ * @param {?string} condition The breakpoint condition.
+ */
+devtools.DebuggerAgent.prototype.addBreakpoint = function(sourceId, line, condition)
+{
+    var script = this.parsedScripts_[sourceId];
+    if (!script)
+        return;
+
+    line = devtools.DebuggerAgent.webkitToV8LineNumber_(line);
+
+    var commandArguments;
+    if (script.getUrl()) {
+        var breakpoints = this.urlToBreakpoints_[script.getUrl()];
+        if (breakpoints && breakpoints[line])
+            return;
+        if (!breakpoints) {
+            breakpoints = {};
+            this.urlToBreakpoints_[script.getUrl()] = breakpoints;
+        }
+
+        var breakpointInfo = new devtools.BreakpointInfo(line);
+        breakpoints[line] = breakpointInfo;
+
+        commandArguments = {
+            "groupId": this.contextId_,
+            "type": "script",
+            "target": script.getUrl(),
+            "line": line,
+            "condition": condition
+        };
+    } else {
+        var breakpointInfo = script.getBreakpointInfo(line);
+        if (breakpointInfo)
+            return;
+
+        breakpointInfo = new devtools.BreakpointInfo(line);
+        script.addBreakpointInfo(breakpointInfo);
+
+        commandArguments = {
+            "groupId": this.contextId_,
+            "type": "scriptId",
+            "target": sourceId,
+            "line": line,
+            "condition": condition
+        };
+    }
+
+    var cmd = new devtools.DebugCommand("setbreakpoint", commandArguments);
+
+    this.requestNumberToBreakpointInfo_[cmd.getSequenceNumber()] = breakpointInfo;
+
+    devtools.DebuggerAgent.sendCommand_(cmd);
+    // Force v8 execution so that it gets to processing the requested command.
+    // It is necessary for being able to change a breakpoint just after it
+    // has been created (since we need an existing breakpoint id for that).
+    RemoteToolsAgent.executeVoidJavaScript();
+};
+
+
+/**
+ * @param {number} sourceId Id of the script for the breakpoint.
+ * @param {number} line Number of the line for the breakpoint.
+ */
+devtools.DebuggerAgent.prototype.removeBreakpoint = function(sourceId, line)
+{
+    var script = this.parsedScripts_[sourceId];
+    if (!script)
+        return;
+
+    line = devtools.DebuggerAgent.webkitToV8LineNumber_(line);
+
+    var breakpointInfo;
+    if (script.getUrl()) {
+        var breakpoints = this.urlToBreakpoints_[script.getUrl()];
+        breakpointInfo = breakpoints[line];
+        delete breakpoints[line];
+    } else {
+        breakpointInfo = script.getBreakpointInfo(line);
+        if (breakpointInfo)
+            script.removeBreakpointInfo(breakpointInfo);
+    }
+
+    if (!breakpointInfo)
+        return;
+
+    breakpointInfo.markAsRemoved();
+
+    var id = breakpointInfo.getV8Id();
+
+    // If we don't know id of this breakpoint in the v8 debugger we cannot send
+    // "clearbreakpoint" request. In that case it will be removed in
+    // "setbreakpoint" response handler when we learn the id.
+    if (id !== -1) {
+        this.requestClearBreakpoint_(id);
+    }
+};
+
+
+/**
+ * @param {number} sourceId Id of the script for the breakpoint.
+ * @param {number} line Number of the line for the breakpoint.
+ * @param {?string} condition New breakpoint condition.
+ */
+devtools.DebuggerAgent.prototype.updateBreakpoint = function(sourceId, line, condition)
+{
+    var script = this.parsedScripts_[sourceId];
+    if (!script)
+        return;
+
+    line = devtools.DebuggerAgent.webkitToV8LineNumber_(line);
+
+    var breakpointInfo;
+    if (script.getUrl()) {
+        var breakpoints = this.urlToBreakpoints_[script.getUrl()];
+        breakpointInfo = breakpoints[line];
+    } else
+        breakpointInfo = script.getBreakpointInfo(line);
+
+    var id = breakpointInfo.getV8Id();
+
+    // If we don't know id of this breakpoint in the v8 debugger we cannot send
+    // the "changebreakpoint" request.
+    if (id !== -1) {
+        // TODO(apavlov): make use of the real values for "enabled" and
+        // "ignoreCount" when appropriate.
+        this.requestChangeBreakpoint_(id, true, condition, null);
+    }
+};
+
+
+/**
+ * Tells the v8 debugger to step into the next statement.
+ */
+devtools.DebuggerAgent.prototype.stepIntoStatement = function()
+{
+    this.stepCommand_("in");
+};
+
+
+/**
+ * Tells the v8 debugger to step out of current function.
+ */
+devtools.DebuggerAgent.prototype.stepOutOfFunction = function()
+{
+    this.stepCommand_("out");
+};
+
+
+/**
+ * Tells the v8 debugger to step over the next statement.
+ */
+devtools.DebuggerAgent.prototype.stepOverStatement = function()
+{
+    this.stepCommand_("next");
+};
+
+
+/**
+ * Tells the v8 debugger to continue execution after it has been stopped on a
+ * breakpoint or an exception.
+ */
+devtools.DebuggerAgent.prototype.resumeExecution = function()
+{
+    this.clearExceptionMessage_();
+    var cmd = new devtools.DebugCommand("continue");
+    devtools.DebuggerAgent.sendCommand_(cmd);
+};
+
+
+/**
+ * Creates exception message and schedules it for addition to the resource upon
+ * backtrace availability.
+ * @param {string} url Resource url.
+ * @param {number} line Resource line number.
+ * @param {string} message Exception text.
+ */
+devtools.DebuggerAgent.prototype.createExceptionMessage_ = function(url, line, message)
+{
+    this.currentExceptionMessage_ = new WebInspector.ConsoleMessage(
+        WebInspector.ConsoleMessage.MessageSource.JS,
+        WebInspector.ConsoleMessage.MessageType.Log,
+        WebInspector.ConsoleMessage.MessageLevel.Error,
+        line,
+        url,
+        0 /* group level */,
+        1 /* repeat count */,
+        "[Exception] " + message);
+};
+
+
+/**
+ * Shows pending exception message that is created with createExceptionMessage_
+ * earlier.
+ */
+devtools.DebuggerAgent.prototype.showPendingExceptionMessage_ = function()
+{
+    if (!this.currentExceptionMessage_)
+        return;
+    var msg = this.currentExceptionMessage_;
+    var resource = WebInspector.resourceURLMap[msg.url];
+    if (resource) {
+        msg.resource = resource;
+        WebInspector.panels.resources.addMessageToResource(resource, msg);
+    } else
+        this.currentExceptionMessage_ = null;
+};
+
+
+/**
+ * Clears exception message from the resource.
+ */
+devtools.DebuggerAgent.prototype.clearExceptionMessage_ = function()
+{
+    if (this.currentExceptionMessage_) {
+        var messageElement = this.currentExceptionMessage_._resourceMessageLineElement;
+        var bubble = messageElement.parentElement;
+        bubble.removeChild(messageElement);
+        if (!bubble.firstChild) {
+            // Last message in bubble removed.
+            bubble.parentElement.removeChild(bubble);
+        }
+        this.currentExceptionMessage_ = null;
+    }
+};
+
+
+/**
+ * @return {boolean} True iff the debugger will pause execution on the
+ * exceptions.
+ */
+devtools.DebuggerAgent.prototype.pauseOnExceptions = function()
+{
+    return this.pauseOnExceptions_;
+};
+
+
+/**
+ * Tells whether to pause in the debugger on the exceptions or not.
+ * @param {boolean} value True iff execution should be stopped in the debugger
+ * on the exceptions.
+ */
+devtools.DebuggerAgent.prototype.setPauseOnExceptions = function(value)
+{
+    this.pauseOnExceptions_ = value;
+};
+
+
+/**
+ * Sends "evaluate" request to the debugger.
+ * @param {Object} arguments Request arguments map.
+ * @param {function(devtools.DebuggerMessage)} callback Callback to be called
+ *     when response is received.
+ */
+devtools.DebuggerAgent.prototype.requestEvaluate = function(arguments, callback)
+{
+    var cmd = new devtools.DebugCommand("evaluate", arguments);
+    devtools.DebuggerAgent.sendCommand_(cmd);
+    this.requestSeqToCallback_[cmd.getSequenceNumber()] = callback;
+};
+
+
+/**
+ * Sends "lookup" request for each unresolved property of the object. When
+ * response is received the properties will be changed with their resolved
+ * values.
+ * @param {Object} object Object whose properties should be resolved.
+ * @param {function(devtools.DebuggerMessage)} Callback to be called when all
+ *     children are resolved.
+ * @param {boolean} noIntrinsic Whether intrinsic properties should be included.
+ */
+devtools.DebuggerAgent.prototype.resolveChildren = function(object, callback, noIntrinsic)
+{
+    if ("handle" in object) {
+        var result = [];
+        devtools.DebuggerAgent.formatObjectProperties_(object, result, noIntrinsic);
+        callback(result);
+    } else {
+        this.requestLookup_([object.ref], function(msg) {
+            var result = [];
+            if (msg.isSuccess()) {
+                var handleToObject = msg.getBody();
+                var resolved = handleToObject[object.ref];
+                devtools.DebuggerAgent.formatObjectProperties_(resolved, result, noIntrinsic);
+                callback(result);
+            } else
+                callback([]);
+        });
+    }
+};
+
+
+/**
+ * Sends "scope" request for the scope object to resolve its variables.
+ * @param {Object} scope Scope to be resolved.
+ * @param {function(Array.<WebInspector.ObjectPropertyProxy>)} callback
+ *     Callback to be called when all scope variables are resolved.
+ */
+devtools.DebuggerAgent.prototype.resolveScope = function(scope, callback)
+{
+    var cmd = new devtools.DebugCommand("scope", {
+        "frameNumber": scope.frameNumber,
+        "number": scope.index,
+        "compactFormat": true
+    });
+    devtools.DebuggerAgent.sendCommand_(cmd);
+    this.requestSeqToCallback_[cmd.getSequenceNumber()] = function(msg) {
+        var result = [];
+        if (msg.isSuccess()) {
+            var scopeObjectJson = msg.getBody().object;
+            devtools.DebuggerAgent.formatObjectProperties_(scopeObjectJson, result, true /* no intrinsic */);
+        }
+        callback(result);
+    };
+};
+
+
+/**
+ * Sends "scopes" request for the frame object to resolve all variables
+ * available in the frame.
+ * @param {number} callFrameId Id of call frame whose variables need to
+ *     be resolved.
+ * @param {function(Object)} callback Callback to be called when all frame
+ *     variables are resolved.
+ */
+devtools.DebuggerAgent.prototype.resolveFrameVariables_ = function(callFrameId, callback)
+{
+    var result = {};
+
+    var frame = this.callFrames_[callFrameId];
+    if (!frame) {
+        callback(result);
+        return;
+    }
+
+    var waitingResponses = 0;
+    function scopeResponseHandler(msg) {
+        waitingResponses--;
+
+        if (msg.isSuccess()) {
+            var properties = msg.getBody().object.properties;
+            for (var j = 0; j < properties.length; j++)
+                result[properties[j].name] = true;
+        }
+
+        // When all scopes are resolved invoke the callback.
+        if (waitingResponses === 0)
+            callback(result);
+    };
+
+    for (var i = 0; i < frame.scopeChain.length; i++) {
+        var scope = frame.scopeChain[i].objectId;
+        if (scope.type === devtools.DebuggerAgent.ScopeType.Global) {
+            // Do not resolve global scope since it takes for too long.
+            // TODO(yurys): allow to send only property names in the response.
+            continue;
+        }
+        var cmd = new devtools.DebugCommand("scope", {
+            "frameNumber": scope.frameNumber,
+            "number": scope.index,
+            "compactFormat": true
+        });
+        devtools.DebuggerAgent.sendCommand_(cmd);
+        this.requestSeqToCallback_[cmd.getSequenceNumber()] = scopeResponseHandler;
+        waitingResponses++;
+    }
+};
+
+/**
+ * Evaluates the expressionString to an object in the call frame and reports
+ * all its properties.
+ * @param{string} expressionString Expression whose properties should be
+ *     collected.
+ * @param{number} callFrameId The frame id.
+ * @param{function(Object result,bool isException)} reportCompletions Callback
+ *     function.
+ */
+devtools.DebuggerAgent.prototype.resolveCompletionsOnFrame = function(expressionString, callFrameId, reportCompletions)
+{
+      if (expressionString) {
+          expressionString = "var obj = " + expressionString +
+              "; var names = {}; for (var n in obj) { names[n] = true; };" +
+              "names;";
+          this.evaluateInCallFrame(
+              callFrameId,
+              expressionString,
+              function(result) {
+                  var names = {};
+                  if (!result.isException) {
+                      var props = result.value.objectId.properties;
+                      // Put all object properties into the map.
+                      for (var i = 0; i < props.length; i++)
+                          names[props[i].name] = true;
+                  }
+                  reportCompletions(names, result.isException);
+              });
+      } else {
+          this.resolveFrameVariables_(callFrameId,
+              function(result) {
+                  reportCompletions(result, false /* isException */);
+              });
+      }
+};
+
+
+/**
+ * @param{number} scriptId
+ * @return {string} Type of the context of the script with specified id.
+ */
+devtools.DebuggerAgent.prototype.getScriptContextType = function(scriptId)
+{
+    return this.parsedScripts_[scriptId].getContextType();
+};
+
+
+/**
+ * Removes specified breakpoint from the v8 debugger.
+ * @param {number} breakpointId Id of the breakpoint in the v8 debugger.
+ */
+devtools.DebuggerAgent.prototype.requestClearBreakpoint_ = function(breakpointId)
+{
+    var cmd = new devtools.DebugCommand("clearbreakpoint", {
+        "breakpoint": breakpointId
+    });
+    devtools.DebuggerAgent.sendCommand_(cmd);
+};
+
+
+/**
+ * Changes breakpoint parameters in the v8 debugger.
+ * @param {number} breakpointId Id of the breakpoint in the v8 debugger.
+ * @param {boolean} enabled Whether to enable the breakpoint.
+ * @param {?string} condition New breakpoint condition.
+ * @param {number} ignoreCount New ignore count for the breakpoint.
+ */
+devtools.DebuggerAgent.prototype.requestChangeBreakpoint_ = function(breakpointId, enabled, condition, ignoreCount)
+{
+    var cmd = new devtools.DebugCommand("changebreakpoint", {
+        "breakpoint": breakpointId,
+        "enabled": enabled,
+        "condition": condition,
+        "ignoreCount": ignoreCount
+    });
+    devtools.DebuggerAgent.sendCommand_(cmd);
+};
+
+
+/**
+ * Sends "backtrace" request to v8.
+ */
+devtools.DebuggerAgent.prototype.requestBacktrace_ = function()
+{
+    var cmd = new devtools.DebugCommand("backtrace", {
+        "compactFormat":true
+    });
+    devtools.DebuggerAgent.sendCommand_(cmd);
+};
+
+
+/**
+ * Sends command to v8 debugger.
+ * @param {devtools.DebugCommand} cmd Command to execute.
+ */
+devtools.DebuggerAgent.sendCommand_ = function(cmd)
+{
+    RemoteDebuggerCommandExecutor.DebuggerCommand(cmd.toJSONProtocol());
+};
+
+
+/**
+ * Tells the v8 debugger to make the next execution step.
+ * @param {string} action "in", "out" or "next" action.
+ */
+devtools.DebuggerAgent.prototype.stepCommand_ = function(action)
+{
+    this.clearExceptionMessage_();
+    var cmd = new devtools.DebugCommand("continue", {
+        "stepaction": action,
+        "stepcount": 1
+    });
+    devtools.DebuggerAgent.sendCommand_(cmd);
+};
+
+
+/**
+ * Sends "lookup" request to v8.
+ * @param {number} handle Handle to the object to lookup.
+ */
+devtools.DebuggerAgent.prototype.requestLookup_ = function(handles, callback)
+{
+    var cmd = new devtools.DebugCommand("lookup", {
+        "compactFormat":true,
+        "handles": handles
+    });
+    devtools.DebuggerAgent.sendCommand_(cmd);
+    this.requestSeqToCallback_[cmd.getSequenceNumber()] = callback;
+};
+
+
+/**
+ * Sets debugger context id for scripts filtering.
+ * @param {number} contextId Id of the inspected page global context.
+ */
+devtools.DebuggerAgent.prototype.setContextId_ = function(contextId)
+{
+    this.contextId_ = contextId;
+
+    // If it's the first time context id is set request scripts list.
+    if (this.requestScriptsWhenContextIdSet_) {
+        this.requestScriptsWhenContextIdSet_ = false;
+        var cmd = new devtools.DebugCommand("scripts", {
+            "includeSource": false
+        });
+        devtools.DebuggerAgent.sendCommand_(cmd);
+        // Force v8 execution so that it gets to processing the requested command.
+        RemoteToolsAgent.executeVoidJavaScript();
+
+        var debuggerAgent = this;
+        this.requestSeqToCallback_[cmd.getSequenceNumber()] = function(msg) {
+            // Handle the response iff the context id hasn't changed since the request
+            // was issued. Otherwise if the context id did change all up-to-date
+            // scripts will be pushed in after compile events and there is no need to
+            // handle the response.
+            if (contextId === debuggerAgent.contextId_)
+                debuggerAgent.handleScriptsResponse_(msg);
+
+            // We received initial scripts response so flush the flag and
+            // see if there is an unhandled backtrace response.
+            debuggerAgent.waitingForInitialScriptsResponse_ = false;
+            if (debuggerAgent.pendingBacktraceResponseHandler_) {
+                debuggerAgent.pendingBacktraceResponseHandler_();
+                debuggerAgent.pendingBacktraceResponseHandler_ = null;
+            }
+        };
+    }
+};
+
+
+/**
+ * Handles output sent by v8 debugger. The output is either asynchronous event
+ * or response to a previously sent request.  See protocol definitioun for more
+ * details on the output format.
+ * @param {string} output
+ */
+devtools.DebuggerAgent.prototype.handleDebuggerOutput_ = function(output)
+{
+    var msg;
+    try {
+        msg = new devtools.DebuggerMessage(output);
+    } catch(e) {
+        debugPrint("Failed to handle debugger response:\n" + e);
+        throw e;
+    }
+
+    if (msg.getType() === "event") {
+        if (msg.getEvent() === "break")
+            this.handleBreakEvent_(msg);
+        else if (msg.getEvent() === "exception")
+            this.handleExceptionEvent_(msg);
+        else if (msg.getEvent() === "afterCompile")
+            this.handleAfterCompileEvent_(msg);
+    } else if (msg.getType() === "response") {
+        if (msg.getCommand() === "scripts")
+            this.invokeCallbackForResponse_(msg);
+        else if (msg.getCommand() === "setbreakpoint")
+            this.handleSetBreakpointResponse_(msg);
+        else if (msg.getCommand() === "clearbreakpoint")
+            this.handleClearBreakpointResponse_(msg);
+        else if (msg.getCommand() === "backtrace")
+            this.handleBacktraceResponse_(msg);
+        else if (msg.getCommand() === "lookup")
+            this.invokeCallbackForResponse_(msg);
+        else if (msg.getCommand() === "evaluate")
+            this.invokeCallbackForResponse_(msg);
+        else if (msg.getCommand() === "scope")
+            this.invokeCallbackForResponse_(msg);
+    }
+};
+
+
+/**
+ * @param {devtools.DebuggerMessage} msg
+ */
+devtools.DebuggerAgent.prototype.handleBreakEvent_ = function(msg)
+{
+    // Force scrips panel to be shown first.
+    WebInspector.currentPanel = WebInspector.panels.scripts;
+
+    var body = msg.getBody();
+
+    var line = devtools.DebuggerAgent.v8ToWwebkitLineNumber_(body.sourceLine);
+    this.requestBacktrace_();
+};
+
+
+/**
+ * @param {devtools.DebuggerMessage} msg
+ */
+devtools.DebuggerAgent.prototype.handleExceptionEvent_ = function(msg)
+{
+    // Force scrips panel to be shown first.
+    WebInspector.currentPanel = WebInspector.panels.scripts;
+
+    var body = msg.getBody();
+    // No script field in the body means that v8 failed to parse the script. We
+    // resume execution on parser errors automatically.
+    if (this.pauseOnExceptions_ && body.script) {
+        var line = devtools.DebuggerAgent.v8ToWwebkitLineNumber_(body.sourceLine);
+        this.createExceptionMessage_(body.script.name, line, body.exception.text);
+        this.requestBacktrace_();
+    } else
+        this.resumeExecution();
+};
+
+
+/**
+ * @param {devtools.DebuggerMessage} msg
+ */
+devtools.DebuggerAgent.prototype.handleScriptsResponse_ = function(msg)
+{
+    var scripts = msg.getBody();
+    for (var i = 0; i < scripts.length; i++) {
+        var script = scripts[i];
+
+        // Skip scripts from other tabs.
+        if (!this.isScriptFromInspectedContext_(script, msg))
+            continue;
+
+        // We may already have received the info in an afterCompile event.
+        if (script.id in this.parsedScripts_)
+            continue;
+        this.addScriptInfo_(script, msg);
+    }
+};
+
+
+/**
+ * @param {Object} script Json object representing script.
+ * @param {devtools.DebuggerMessage} msg Debugger response.
+ */
+devtools.DebuggerAgent.prototype.isScriptFromInspectedContext_ = function(script, msg)
+{
+    if (!script.context) {
+        // Always ignore scripts from the utility context.
+        return false;
+    }
+    var context = msg.lookup(script.context.ref);
+    var scriptContextId = context.data;
+    if (typeof scriptContextId === "undefined")
+        return false; // Always ignore scripts from the utility context.
+    if (this.contextId_ === null)
+        return true;
+    // Find the id from context data. The context data has the format "type,id".
+    var comma = context.data.indexOf(",");
+    if (comma < 0)
+        return false;
+    return (context.data.substring(comma + 1) == this.contextId_);
+};
+
+
+/**
+ * @param {devtools.DebuggerMessage} msg
+ */
+devtools.DebuggerAgent.prototype.handleSetBreakpointResponse_ = function(msg)
+{
+    var requestSeq = msg.getRequestSeq();
+    var breakpointInfo = this.requestNumberToBreakpointInfo_[requestSeq];
+    if (!breakpointInfo) {
+        // TODO(yurys): handle this case
+        return;
+    }
+    delete this.requestNumberToBreakpointInfo_[requestSeq];
+    if (!msg.isSuccess()) {
+        // TODO(yurys): handle this case
+        return;
+    }
+    var idInV8 = msg.getBody().breakpoint;
+    breakpointInfo.setV8Id(idInV8);
+
+    if (breakpointInfo.isRemoved())
+        this.requestClearBreakpoint_(idInV8);
+};
+
+
+/**
+ * @param {devtools.DebuggerMessage} msg
+ */
+devtools.DebuggerAgent.prototype.handleAfterCompileEvent_ = function(msg)
+{
+    if (!this.contextId_) {
+        // Ignore scripts delta if main request has not been issued yet.
+        return;
+    }
+    var script = msg.getBody().script;
+
+    // Ignore scripts from other tabs.
+    if (!this.isScriptFromInspectedContext_(script, msg))
+        return;
+    this.addScriptInfo_(script, msg);
+};
+
+
+/**
+ * Adds the script info to the local cache. This method assumes that the script
+ * is not in the cache yet.
+ * @param {Object} script Script json object from the debugger message.
+ * @param {devtools.DebuggerMessage} msg Debugger message containing the script
+ *     data.
+ */
+devtools.DebuggerAgent.prototype.addScriptInfo_ = function(script, msg)
+{
+    var context = msg.lookup(script.context.ref);
+    var contextType;
+    // Find the type from context data. The context data has the format
+    // "type,id".
+    var comma = context.data.indexOf(",");
+    if (comma < 0)
+        return
+    contextType = context.data.substring(0, comma);
+    this.parsedScripts_[script.id] = new devtools.ScriptInfo(script.id, script.name, script.lineOffset, contextType);
+    if (this.scriptsPanelInitialized_) {
+        // Only report script as parsed after scripts panel has been shown.
+        WebInspector.parsedScriptSource(script.id, script.name, script.source, script.lineOffset);
+    }
+};
+
+
+/**
+ * @param {devtools.DebuggerMessage} msg
+ */
+devtools.DebuggerAgent.prototype.handleClearBreakpointResponse_ = function(msg)
+{
+    // Do nothing.
+};
+
+
+/**
+ * Handles response to "backtrace" command.
+ * @param {devtools.DebuggerMessage} msg
+ */
+devtools.DebuggerAgent.prototype.handleBacktraceResponse_ = function(msg)
+{
+    if (this.waitingForInitialScriptsResponse_)
+        this.pendingBacktraceResponseHandler_ = this.doHandleBacktraceResponse_.bind(this, msg);
+    else
+        this.doHandleBacktraceResponse_(msg);
+};
+
+
+/**
+ * @param {devtools.DebuggerMessage} msg
+ */
+devtools.DebuggerAgent.prototype.doHandleBacktraceResponse_ = function(msg)
+{
+    var frames = msg.getBody().frames;
+    this.callFrames_ = [];
+    for (var i = 0; i <  frames.length; ++i)
+        this.callFrames_.push(this.formatCallFrame_(frames[i]));
+    WebInspector.pausedScript(this.callFrames_);
+    this.showPendingExceptionMessage_();
+    InspectorFrontendHost.activateWindow();
+};
+
+
+/**
+ * Evaluates code on given callframe.
+ */
+devtools.DebuggerAgent.prototype.evaluateInCallFrame = function(callFrameId, code, callback)
+{
+    var callFrame = this.callFrames_[callFrameId];
+    callFrame.evaluate_(code, callback);
+};
+
+
+/**
+ * Handles response to a command by invoking its callback (if any).
+ * @param {devtools.DebuggerMessage} msg
+ * @return {boolean} Whether a callback for the given message was found and
+ *     excuted.
+ */
+devtools.DebuggerAgent.prototype.invokeCallbackForResponse_ = function(msg)
+{
+    var callback = this.requestSeqToCallback_[msg.getRequestSeq()];
+    if (!callback) {
+        // It may happend if reset was called.
+        return false;
+    }
+    delete this.requestSeqToCallback_[msg.getRequestSeq()];
+    callback(msg);
+    return true;
+};
+
+
+/**
+ * @param {Object} stackFrame Frame json object from "backtrace" response.
+ * @return {!devtools.CallFrame} Object containing information related to the
+ *     call frame in the format expected by ScriptsPanel and its panes.
+ */
+devtools.DebuggerAgent.prototype.formatCallFrame_ = function(stackFrame)
+{
+    var func = stackFrame.func;
+    var sourceId = func.scriptId;
+
+    // Add service script if it does not exist.
+    var existingScript = this.parsedScripts_[sourceId];
+    if (!existingScript) {
+        this.parsedScripts_[sourceId] = new devtools.ScriptInfo(sourceId, null /* name */, 0 /* line */, "unknown" /* type */, true /* unresolved */);
+        WebInspector.parsedScriptSource(sourceId, null, null, 0);
+    }
+
+    var funcName = func.name || func.inferredName || "(anonymous function)";
+    var line = devtools.DebuggerAgent.v8ToWwebkitLineNumber_(stackFrame.line);
+
+    // Add basic scope chain info with scope variables.
+    var scopeChain = [];
+    var ScopeType = devtools.DebuggerAgent.ScopeType;
+    for (var i = 0; i < stackFrame.scopes.length; i++) {
+        var scope = stackFrame.scopes[i];
+        scope.frameNumber = stackFrame.index;
+        var scopeObjectProxy = new WebInspector.ObjectProxy(0, scope, [], 0, "", true);
+        scopeObjectProxy.isScope = true;
+        switch(scope.type) {
+            case ScopeType.Global:
+                scopeObjectProxy.isDocument = true;
+                break;
+            case ScopeType.Local:
+                scopeObjectProxy.isLocal = true;
+                scopeObjectProxy.thisObject = devtools.DebuggerAgent.formatObjectProxy_(stackFrame.receiver);
+                break;
+            case ScopeType.With:
+            // Catch scope is treated as a regular with scope by WebKit so we
+            // also treat it this way.
+            case ScopeType.Catch:
+                scopeObjectProxy.isWithBlock = true;
+                break;
+            case ScopeType.Closure:
+                scopeObjectProxy.isClosure = true;
+                break;
+        }
+        scopeChain.push(scopeObjectProxy);
+    }
+    return new devtools.CallFrame(stackFrame.index, "function", funcName, sourceId, line, scopeChain);
+};
+
+
+/**
+ * Collects properties for an object from the debugger response.
+ * @param {Object} object An object from the debugger protocol response.
+ * @param {Array.<WebInspector.ObjectPropertyProxy>} result An array to put the
+ *     properties into.
+ * @param {boolean} noIntrinsic Whether intrinsic properties should be
+ *     included.
+ */
+devtools.DebuggerAgent.formatObjectProperties_ = function(object, result, noIntrinsic)
+{
+    devtools.DebuggerAgent.propertiesToProxies_(object.properties, result);
+    if (noIntrinsic)
+        return;
+
+    result.push(new WebInspector.ObjectPropertyProxy("__proto__", devtools.DebuggerAgent.formatObjectProxy_(object.protoObject)));
+    result.push(new WebInspector.ObjectPropertyProxy("constructor", devtools.DebuggerAgent.formatObjectProxy_(object.constructorFunction)));
+    // Don't add 'prototype' property since it is one of the regualar properties.
+};
+
+
+/**
+ * For each property in "properties" creates its proxy representative.
+ * @param {Array.<Object>} properties Receiver properties or locals array from
+ *     "backtrace" response.
+ * @param {Array.<WebInspector.ObjectPropertyProxy>} Results holder.
+ */
+devtools.DebuggerAgent.propertiesToProxies_ = function(properties, result)
+{
+    var map = {};
+    for (var i = 0; i < properties.length; ++i) {
+        var property = properties[i];
+        var name = String(property.name);
+        if (name in map)
+            continue;
+        map[name] = true;
+        var value = devtools.DebuggerAgent.formatObjectProxy_(property.value);
+        var propertyProxy = new WebInspector.ObjectPropertyProxy(name, value);
+        result.push(propertyProxy);
+    }
+};
+
+
+/**
+ * @param {Object} v An object reference from the debugger response.
+ * @return {*} The value representation expected by ScriptsPanel.
+ */
+devtools.DebuggerAgent.formatObjectProxy_ = function(v)
+{
+    var description;
+    var hasChildren = false;
+    if (v.type === "object") {
+        description = v.className;
+        hasChildren = true;
+    } else if (v.type === "function") {
+        if (v.source)
+            description = v.source;
+        else
+            description = "function " + v.name + "()";
+        hasChildren = true;
+    } else if (v.type === "undefined")
+        description = "undefined";
+    else if (v.type === "null")
+        description = "null";
+    else if (typeof v.value !== "undefined") {
+        // Check for undefined and null types before checking the value, otherwise
+        // null/undefined may have blank value.
+        description = v.value;
+    } else
+        description = "<unresolved ref: " + v.ref + ", type: " + v.type + ">";
+
+    var proxy = new WebInspector.ObjectProxy(0, v, [], 0, description, hasChildren);
+    proxy.type = v.type;
+    proxy.isV8Ref = true;
+    return proxy;
+};
+
+
+/**
+ * Converts line number from Web Inspector UI(1-based) to v8(0-based).
+ * @param {number} line Resource line number in Web Inspector UI.
+ * @return {number} The line number in v8.
+ */
+devtools.DebuggerAgent.webkitToV8LineNumber_ = function(line)
+{
+    return line - 1;
+};
+
+
+/**
+ * Converts line number from v8(0-based) to Web Inspector UI(1-based).
+ * @param {number} line Resource line number in v8.
+ * @return {number} The line number in Web Inspector.
+ */
+devtools.DebuggerAgent.v8ToWwebkitLineNumber_ = function(line)
+{
+    return line + 1;
+};
+
+
+/**
+ * @param {number} scriptId Id of the script.
+ * @param {?string} url Script resource URL if any.
+ * @param {number} lineOffset First line 0-based offset in the containing
+ *     document.
+ * @param {string} contextType Type of the script's context:
+ *     "page" - regular script from html page
+ *     "injected" - extension content script
+ * @param {bool} opt_isUnresolved If true, script will not be resolved.
+ * @constructor
+ */
+devtools.ScriptInfo = function(scriptId, url, lineOffset, contextType, opt_isUnresolved)
+{
+    this.scriptId_ = scriptId;
+    this.lineOffset_ = lineOffset;
+    this.contextType_ = contextType;
+    this.url_ = url;
+    this.isUnresolved_ = opt_isUnresolved;
+
+    this.lineToBreakpointInfo_ = {};
+};
+
+
+/**
+ * @return {number}
+ */
+devtools.ScriptInfo.prototype.getLineOffset = function()
+{
+    return this.lineOffset_;
+};
+
+
+/**
+ * @return {string}
+ */
+devtools.ScriptInfo.prototype.getContextType = function()
+{
+    return this.contextType_;
+};
+
+
+/**
+ * @return {?string}
+ */
+devtools.ScriptInfo.prototype.getUrl = function()
+{
+    return this.url_;
+};
+
+
+/**
+ * @return {?bool}
+ */
+devtools.ScriptInfo.prototype.isUnresolved = function()
+{
+    return this.isUnresolved_;
+};
+
+
+/**
+ * @param {number} line 0-based line number in the script.
+ * @return {?devtools.BreakpointInfo} Information on a breakpoint at the
+ *     specified line in the script or undefined if there is no breakpoint at
+ *     that line.
+ */
+devtools.ScriptInfo.prototype.getBreakpointInfo = function(line)
+{
+    return this.lineToBreakpointInfo_[line];
+};
+
+
+/**
+ * Adds breakpoint info to the script.
+ * @param {devtools.BreakpointInfo} breakpoint
+ */
+devtools.ScriptInfo.prototype.addBreakpointInfo = function(breakpoint)
+{
+    this.lineToBreakpointInfo_[breakpoint.getLine()] = breakpoint;
+};
+
+
+/**
+ * @param {devtools.BreakpointInfo} breakpoint Breakpoint info to be removed.
+ */
+devtools.ScriptInfo.prototype.removeBreakpointInfo = function(breakpoint)
+{
+    var line = breakpoint.getLine();
+    delete this.lineToBreakpointInfo_[line];
+};
+
+
+
+/**
+ * @param {number} line Breakpoint 0-based line number in the containing script.
+ * @constructor
+ */
+devtools.BreakpointInfo = function(line)
+{
+    this.line_ = line;
+    this.v8id_ = -1;
+    this.removed_ = false;
+};
+
+
+/**
+ * @return {number}
+ */
+devtools.BreakpointInfo.prototype.getLine = function(n)
+{
+    return this.line_;
+};
+
+
+/**
+ * @return {number} Unique identifier of this breakpoint in the v8 debugger.
+ */
+devtools.BreakpointInfo.prototype.getV8Id = function(n)
+{
+    return this.v8id_;
+};
+
+
+/**
+ * Sets id of this breakpoint in the v8 debugger.
+ * @param {number} id
+ */
+devtools.BreakpointInfo.prototype.setV8Id = function(id)
+{
+    this.v8id_ = id;
+};
+
+
+/**
+ * Marks this breakpoint as removed from the  front-end.
+ */
+devtools.BreakpointInfo.prototype.markAsRemoved = function()
+{
+    this.removed_ = true;
+};
+
+
+/**
+ * @return {boolean} Whether this breakpoint has been removed from the
+ *     front-end.
+ */
+devtools.BreakpointInfo.prototype.isRemoved = function()
+{
+    return this.removed_;
+};
+
+
+/**
+ * Call stack frame data.
+ * @param {string} id CallFrame id.
+ * @param {string} type CallFrame type.
+ * @param {string} functionName CallFrame type.
+ * @param {string} sourceID Source id.
+ * @param {number} line Source line.
+ * @param {Array.<Object>} scopeChain Array of scoped objects.
+ * @construnctor
+ */
+devtools.CallFrame = function(id, type, functionName, sourceID, line, scopeChain)
+{
+    this.id = id;
+    this.type = type;
+    this.functionName = functionName;
+    this.sourceID = sourceID;
+    this.line = line;
+    this.scopeChain = scopeChain;
+};
+
+
+/**
+ * This method issues asynchronous evaluate request, reports result to the
+ * callback.
+ * @param {string} expression An expression to be evaluated in the context of
+ *     this call frame.
+ * @param {function(Object):undefined} callback Callback to report result to.
+ */
+devtools.CallFrame.prototype.evaluate_ = function(expression, callback)
+{
+    devtools.tools.getDebuggerAgent().requestEvaluate({
+            "expression": expression,
+            "frame": this.id,
+            "global": false,
+            "disable_break": false,
+            "compactFormat": true
+        },
+        function(response) {
+            var result = {};
+            if (response.isSuccess())
+                result.value = devtools.DebuggerAgent.formatObjectProxy_(response.getBody());
+            else {
+                result.value = response.getMessage();
+                result.isException = true;
+            }
+            callback(result);
+        });
+};
+
+
+/**
+ * JSON based commands sent to v8 debugger.
+ * @param {string} command Name of the command to execute.
+ * @param {Object} opt_arguments Command-specific arguments map.
+ * @constructor
+ */
+devtools.DebugCommand = function(command, opt_arguments)
+{
+    this.command_ = command;
+    this.type_ = "request";
+    this.seq_ = ++devtools.DebugCommand.nextSeq_;
+    if (opt_arguments)
+        this.arguments_ = opt_arguments;
+};
+
+
+/**
+ * Next unique number to be used as debugger request sequence number.
+ * @type {number}
+ */
+devtools.DebugCommand.nextSeq_ = 1;
+
+
+/**
+ * @return {number}
+ */
+devtools.DebugCommand.prototype.getSequenceNumber = function()
+{
+    return this.seq_;
+};
+
+
+/**
+ * @return {string}
+ */
+devtools.DebugCommand.prototype.toJSONProtocol = function()
+{
+    var json = {
+        "seq": this.seq_,
+        "type": this.type_,
+        "command": this.command_
+    }
+    if (this.arguments_)
+        json.arguments = this.arguments_;
+    return JSON.stringify(json);
+};
+
+
+/**
+ * JSON messages sent from v8 debugger. See protocol definition for more
+ * details: http://code.google.com/p/v8/wiki/DebuggerProtocol
+ * @param {string} msg Raw protocol packet as JSON string.
+ * @constructor
+ */
+devtools.DebuggerMessage = function(msg)
+{
+    this.packet_ = JSON.parse(msg);
+    this.refs_ = [];
+    if (this.packet_.refs) {
+        for (var i = 0; i < this.packet_.refs.length; i++)
+            this.refs_[this.packet_.refs[i].handle] = this.packet_.refs[i];
+    }
+};
+
+
+/**
+ * @return {string} The packet type.
+ */
+devtools.DebuggerMessage.prototype.getType = function()
+{
+    return this.packet_.type;
+};
+
+
+/**
+ * @return {?string} The packet event if the message is an event.
+ */
+devtools.DebuggerMessage.prototype.getEvent = function()
+{
+    return this.packet_.event;
+};
+
+
+/**
+ * @return {?string} The packet command if the message is a response to a
+ *     command.
+ */
+devtools.DebuggerMessage.prototype.getCommand = function()
+{
+    return this.packet_.command;
+};
+
+
+/**
+ * @return {number} The packet request sequence.
+ */
+devtools.DebuggerMessage.prototype.getRequestSeq = function()
+{
+    return this.packet_.request_seq;
+};
+
+
+/**
+ * @return {number} Whether the v8 is running after processing the request.
+ */
+devtools.DebuggerMessage.prototype.isRunning = function()
+{
+    return this.packet_.running ? true : false;
+};
+
+
+/**
+ * @return {boolean} Whether the request succeeded.
+ */
+devtools.DebuggerMessage.prototype.isSuccess = function()
+{
+    return this.packet_.success ? true : false;
+};
+
+
+/**
+ * @return {string}
+ */
+devtools.DebuggerMessage.prototype.getMessage = function()
+{
+    return this.packet_.message;
+};
+
+
+/**
+ * @return {Object} Parsed message body json.
+ */
+devtools.DebuggerMessage.prototype.getBody = function()
+{
+    return this.packet_.body;
+};
+
+
+/**
+ * @param {number} handle Object handle.
+ * @return {?Object} Returns the object with the handle if it was sent in this
+ *    message(some objects referenced by handles may be missing in the message).
+ */
+devtools.DebuggerMessage.prototype.lookup = function(handle)
+{
+    return this.refs_[handle];
+};
diff --git a/WebKit/chromium/src/js/DevTools.js b/WebKit/chromium/src/js/DevTools.js
new file mode 100644
index 0000000..dcb181b
--- /dev/null
+++ b/WebKit/chromium/src/js/DevTools.js
@@ -0,0 +1,504 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * FIXME: change field naming style to use trailing underscore.
+ * @fileoverview Tools is a main class that wires all components of the
+ * DevTools frontend together. It is also responsible for overriding existing
+ * WebInspector functionality while it is getting upstreamed into WebCore.
+ */
+
+/**
+ * Dispatches raw message from the host.
+ * @param {string} remoteName
+ * @prama {string} methodName
+ * @param {string} param1, param2, param3 Arguments to dispatch.
+ */
+devtools$$dispatch = function(remoteName, methodName, param1, param2, param3)
+{
+    remoteName = "Remote" + remoteName.substring(0, remoteName.length - 8);
+    var agent = window[remoteName];
+    if (!agent) {
+        debugPrint("No remote agent '" + remoteName + "' found.");
+        return;
+    }
+    var method = agent[methodName];
+    if (!method) {
+        debugPrint("No method '" + remoteName + "." + methodName + "' found.");
+        return;
+    }
+    method.call(this, param1, param2, param3);
+};
+
+
+devtools.ToolsAgent = function()
+{
+    RemoteToolsAgent.didDispatchOn = WebInspector.Callback.processCallback;
+    RemoteToolsAgent.frameNavigate = this.frameNavigate_.bind(this);
+    RemoteToolsAgent.dispatchOnClient = this.dispatchOnClient_.bind(this);
+    this.debuggerAgent_ = new devtools.DebuggerAgent();
+    this.profilerAgent_ = new devtools.ProfilerAgent();
+};
+
+
+/**
+ * Resets tools agent to its initial state.
+ */
+devtools.ToolsAgent.prototype.reset = function()
+{
+    this.debuggerAgent_.reset();
+};
+
+
+/**
+ * @param {string} script Script exression to be evaluated in the context of the
+ *     inspected page.
+ * @param {function(Object|string, boolean):undefined} opt_callback Function to
+ *     call with the result.
+ */
+devtools.ToolsAgent.prototype.evaluateJavaScript = function(script, opt_callback)
+{
+    InspectorBackend.evaluate(script, opt_callback || function() {});
+};
+
+
+/**
+ * @return {devtools.DebuggerAgent} Debugger agent instance.
+ */
+devtools.ToolsAgent.prototype.getDebuggerAgent = function()
+{
+    return this.debuggerAgent_;
+};
+
+
+/**
+ * @return {devtools.ProfilerAgent} Profiler agent instance.
+ */
+devtools.ToolsAgent.prototype.getProfilerAgent = function()
+{
+    return this.profilerAgent_;
+};
+
+
+/**
+ * @param {string} url Url frame navigated to.
+ * @see tools_agent.h
+ * @private
+ */
+devtools.ToolsAgent.prototype.frameNavigate_ = function(url)
+{
+    this.reset();
+    // Do not reset Profiles panel.
+    var profiles = null;
+    if ("profiles" in WebInspector.panels) {
+        profiles = WebInspector.panels["profiles"];
+        delete WebInspector.panels["profiles"];
+    }
+    WebInspector.reset();
+    if (profiles !== null)
+        WebInspector.panels["profiles"] = profiles;
+};
+
+
+/**
+ * @param {string} message Serialized call to be dispatched on WebInspector.
+ * @private
+ */
+devtools.ToolsAgent.prototype.dispatchOnClient_ = function(message)
+{
+    var args = JSON.parse(message);
+    var methodName = args[0];
+    var parameters = args.slice(1);
+    WebInspector[methodName].apply(WebInspector, parameters);
+};
+
+
+/**
+ * Evaluates js expression.
+ * @param {string} expr
+ */
+devtools.ToolsAgent.prototype.evaluate = function(expr)
+{
+    RemoteToolsAgent.evaluate(expr);
+};
+
+
+/**
+ * Enables / disables resources panel in the ui.
+ * @param {boolean} enabled New panel status.
+ */
+WebInspector.setResourcesPanelEnabled = function(enabled)
+{
+    InspectorBackend._resourceTrackingEnabled = enabled;
+    WebInspector.panels.resources.reset();
+};
+
+
+/**
+ * Prints string  to the inspector console or shows alert if the console doesn't
+ * exist.
+ * @param {string} text
+ */
+function debugPrint(text) {
+    var console = WebInspector.console;
+    if (console) {
+        console.addMessage(new WebInspector.ConsoleMessage(
+            WebInspector.ConsoleMessage.MessageSource.JS,
+            WebInspector.ConsoleMessage.MessageType.Log,
+            WebInspector.ConsoleMessage.MessageLevel.Log,
+            1, "chrome://devtools/<internal>", undefined, -1, text));
+    } else
+        alert(text);
+}
+
+
+/**
+ * Global instance of the tools agent.
+ * @type {devtools.ToolsAgent}
+ */
+devtools.tools = null;
+
+
+var context = {};  // Used by WebCore's inspector routines.
+
+///////////////////////////////////////////////////////////////////////////////
+// Here and below are overrides to existing WebInspector methods only.
+// TODO(pfeldman): Patch WebCore and upstream changes.
+var oldLoaded = WebInspector.loaded;
+WebInspector.loaded = function()
+{
+    devtools.tools = new devtools.ToolsAgent();
+    devtools.tools.reset();
+
+    Preferences.ignoreWhitespace = false;
+    Preferences.samplingCPUProfiler = true;
+    Preferences.heapProfilerPresent = true;
+    oldLoaded.call(this);
+
+    InspectorFrontendHost.loaded();
+};
+
+
+(function()
+{
+
+    /**
+     * Handles an F3 keydown event to focus the Inspector search box.
+     * @param {KeyboardEvent} event Event to optionally handle
+     * @return {boolean} whether the event has been handled
+     */
+    function handleF3Keydown(event) {
+        if (event.keyIdentifier === "F3" && !event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey) {
+            var searchField = document.getElementById("search");
+            searchField.focus();
+            searchField.select();
+            event.preventDefault();
+            return true;
+        }
+        return false;
+    }
+
+
+    var oldKeyDown = WebInspector.documentKeyDown;
+    /**
+     * This override allows to intercept keydown events we want to handle in a
+     * custom way. Some nested documents (iframes) delegate keydown handling to
+     * WebInspector.documentKeyDown (e.g. SourceFrame).
+     * @param {KeyboardEvent} event
+     * @override
+     */
+    WebInspector.documentKeyDown = function(event) {
+        var isHandled = handleF3Keydown(event);
+        if (!isHandled) {
+            // Mute refresh action.
+            if (event.keyIdentifier === "F5")
+                event.preventDefault();
+            else if (event.keyIdentifier === "U+0052" /* "R" */ && (event.ctrlKey || event.metaKey))
+                event.preventDefault();
+            else
+                oldKeyDown.call(this, event);
+        }
+    };
+})();
+
+
+/**
+ * This override is necessary for adding script source asynchronously.
+ * @override
+ */
+WebInspector.ScriptView.prototype.setupSourceFrameIfNeeded = function()
+{
+    if (!this._frameNeedsSetup)
+        return;
+
+    this.attach();
+
+    if (this.script.source)
+        this.didResolveScriptSource_();
+    else {
+        var self = this;
+        devtools.tools.getDebuggerAgent().resolveScriptSource(
+            this.script.sourceID,
+            function(source) {
+                self.script.source = source || WebInspector.UIString("<source is not available>");
+                self.didResolveScriptSource_();
+            });
+    }
+};
+
+
+/**
+ * Performs source frame setup when script source is aready resolved.
+ */
+WebInspector.ScriptView.prototype.didResolveScriptSource_ = function()
+{
+    this.sourceFrame.setContent("text/javascript", this.script.source);
+    this._sourceFrameSetup = true;
+    delete this._frameNeedsSetup;
+};
+
+
+/**
+ * @param {string} type Type of the the property value("object" or "function").
+ * @param {string} className Class name of the property value.
+ * @constructor
+ */
+WebInspector.UnresolvedPropertyValue = function(type, className)
+{
+    this.type = type;
+    this.className = className;
+};
+
+
+(function()
+{
+    var oldShow = WebInspector.ScriptsPanel.prototype.show;
+    WebInspector.ScriptsPanel.prototype.show =  function()
+    {
+        devtools.tools.getDebuggerAgent().initUI();
+        this.enableToggleButton.visible = false;
+        oldShow.call(this);
+    };
+})();
+
+
+(function InterceptProfilesPanelEvents()
+{
+    var oldShow = WebInspector.ProfilesPanel.prototype.show;
+    WebInspector.ProfilesPanel.prototype.show = function()
+    {
+        devtools.tools.getProfilerAgent().initializeProfiling();
+        this.enableToggleButton.visible = false;
+        oldShow.call(this);
+        // Show is called on every show event of a panel, so
+        // we only need to intercept it once.
+        WebInspector.ProfilesPanel.prototype.show = oldShow;
+    };
+})();
+
+
+/*
+ * @override
+ * TODO(mnaganov): Restore l10n when it will be agreed that it is needed.
+ */
+WebInspector.UIString = function(string)
+{
+    return String.vsprintf(string, Array.prototype.slice.call(arguments, 1));
+};
+
+
+// There is no clear way of setting frame title yet. So sniffing main resource
+// load.
+(function OverrideUpdateResource() {
+    var originalUpdateResource = WebInspector.updateResource;
+    WebInspector.updateResource = function(identifier, payload)
+    {
+        originalUpdateResource.call(this, identifier, payload);
+        var resource = this.resources[identifier];
+        if (resource && resource.mainResource && resource.finished)
+            document.title = WebInspector.UIString("Developer Tools - %s", resource.url);
+    };
+})();
+
+
+// Highlight extension content scripts in the scripts list.
+(function () {
+    var original = WebInspector.ScriptsPanel.prototype._addScriptToFilesMenu;
+    WebInspector.ScriptsPanel.prototype._addScriptToFilesMenu = function(script)
+    {
+        var result = original.apply(this, arguments);
+        var debuggerAgent = devtools.tools.getDebuggerAgent();
+        var type = debuggerAgent.getScriptContextType(script.sourceID);
+        var option = script.filesSelectOption;
+        if (type === "injected" && option)
+            option.addStyleClass("injected");
+        return result;
+    };
+})();
+
+
+/** Pending WebKit upstream by apavlov). Fixes iframe vs drag problem. */
+(function()
+{
+    var originalDragStart = WebInspector.elementDragStart;
+    WebInspector.elementDragStart = function(element)
+    {
+        if (element) {
+            var glassPane = document.createElement("div");
+            glassPane.style.cssText = "position:absolute;width:100%;height:100%;opacity:0;z-index:1";
+            glassPane.id = "glass-pane-for-drag";
+            element.parentElement.appendChild(glassPane);
+        }
+
+        originalDragStart.apply(this, arguments);
+    };
+
+    var originalDragEnd = WebInspector.elementDragEnd;
+    WebInspector.elementDragEnd = function()
+    {
+        originalDragEnd.apply(this, arguments);
+
+        var glassPane = document.getElementById("glass-pane-for-drag");
+        if (glassPane)
+            glassPane.parentElement.removeChild(glassPane);
+    };
+})();
+
+
+(function () {
+var orig = InjectedScriptAccess.prototype.getProperties;
+InjectedScriptAccess.prototype.getProperties = function(objectProxy, ignoreHasOwnProperty, abbreviate, callback)
+{
+    if (objectProxy.isScope)
+        devtools.tools.getDebuggerAgent().resolveScope(objectProxy.objectId, callback);
+    else if (objectProxy.isV8Ref)
+        devtools.tools.getDebuggerAgent().resolveChildren(objectProxy.objectId, callback, false);
+    else
+        orig.apply(this, arguments);
+};
+})();
+
+
+(function()
+{
+InjectedScriptAccess.prototype.evaluateInCallFrame = function(callFrameId, code, objectGroup, callback)
+{
+    //TODO(pfeldman): remove once 49084 is rolled.
+    if (!callback)
+        callback = objectGroup;
+    devtools.tools.getDebuggerAgent().evaluateInCallFrame(callFrameId, code, callback);
+};
+})();
+
+
+WebInspector.resourceTrackingWasEnabled = function()
+{
+      InspectorBackend._resourceTrackingEnabled = true;
+      this.panels.resources.resourceTrackingWasEnabled();
+};
+
+WebInspector.resourceTrackingWasDisabled = function()
+{
+      InspectorBackend._resourceTrackingEnabled = false;
+      this.panels.resources.resourceTrackingWasDisabled();
+};
+
+(function()
+{
+var orig = WebInspector.ConsoleMessage.prototype.setMessageBody;
+WebInspector.ConsoleMessage.prototype.setMessageBody = function(args)
+{
+    for (var i = 0; i < args.length; ++i) {
+        if (typeof args[i] === "string")
+            args[i] = WebInspector.ObjectProxy.wrapPrimitiveValue(args[i]);
+    }
+    orig.call(this, args);
+};
+})();
+
+
+(function()
+{
+var orig = InjectedScriptAccess.prototype.getCompletions;
+InjectedScriptAccess.prototype.getCompletions = function(expressionString, includeInspectorCommandLineAPI, callFrameId, reportCompletions)
+{
+    if (typeof callFrameId === "number")
+        devtools.tools.getDebuggerAgent().resolveCompletionsOnFrame(expressionString, callFrameId, reportCompletions);
+    else
+        return orig.apply(this, arguments);
+};
+})();
+
+
+(function()
+{
+WebInspector.ElementsPanel.prototype._nodeSearchButtonClicked = function( event)
+{
+    InspectorBackend.toggleNodeSearch();
+    this.nodeSearchButton.toggled = !this.nodeSearchButton.toggled;
+};
+})();
+
+
+// We need to have a place for postponed tasks
+// which should be executed when all the messages between agent and frontend
+// are processed.
+
+WebInspector.runAfterPendingDispatchesQueue = [];
+
+WebInspector.TestController.prototype.runAfterPendingDispatches = function(callback)
+{
+    WebInspector.runAfterPendingDispatchesQueue.push(callback);
+};
+
+WebInspector.queuesAreEmpty = function()
+{
+    var copy = this.runAfterPendingDispatchesQueue.slice();
+    this.runAfterPendingDispatchesQueue = [];
+    for (var i = 0; i < copy.length; ++i)
+        copy[i].call(this);
+};
+
+(function()
+{
+var originalAddToFrame = InspectorFrontendHost.addResourceSourceToFrame;
+InspectorFrontendHost.addResourceSourceToFrame = function(identifier, element)
+{
+    var resource = WebInspector.resources[identifier];
+    if (!resource)
+        return;
+    originalAddToFrame.call(this, identifier, resource.mimeType, element);
+};
+})();
+
+WebInspector.pausedScript = function(callFrames)
+{
+    this.panels.scripts.debuggerPaused(callFrames);
+};
diff --git a/WebKit/chromium/src/js/DevToolsHostStub.js b/WebKit/chromium/src/js/DevToolsHostStub.js
new file mode 100644
index 0000000..2ee15f8
--- /dev/null
+++ b/WebKit/chromium/src/js/DevToolsHostStub.js
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @fileoverview These stubs emulate backend functionality and allows
+ * DevTools frontend to function as a standalone web app.
+ */
+
+if (!window["RemoteDebuggerAgent"]) {
+
+/**
+ * FIXME: change field naming style to use trailing underscore.
+ * @constructor
+ */
+RemoteDebuggerAgentStub = function()
+{
+};
+
+
+RemoteDebuggerAgentStub.prototype.getContextId = function()
+{
+    RemoteDebuggerAgent.setContextId(3);
+};
+
+
+/**
+ * @constructor
+ */
+RemoteProfilerAgentStub = function()
+{
+};
+
+
+RemoteProfilerAgentStub.prototype.getActiveProfilerModules = function()
+{
+    ProfilerStubHelper.GetInstance().getActiveProfilerModules();
+};
+
+
+RemoteProfilerAgentStub.prototype.getLogLines = function(pos)
+{
+    ProfilerStubHelper.GetInstance().getLogLines(pos);
+};
+
+
+/**
+ * @constructor
+ */
+RemoteToolsAgentStub = function()
+{
+};
+
+
+RemoteToolsAgentStub.prototype.dispatchOnInjectedScript = function()
+{
+};
+
+
+RemoteToolsAgentStub.prototype.dispatchOnInspectorController = function()
+{
+};
+
+
+RemoteToolsAgentStub.prototype.executeVoidJavaScript = function()
+{
+};
+
+
+/**
+ * @constructor
+ */
+ProfilerStubHelper = function()
+{
+    this.activeProfilerModules_ = devtools.ProfilerAgent.ProfilerModules.PROFILER_MODULE_NONE;
+    this.heapProfSample_ = 0;
+    this.log_ = '';
+};
+
+
+ProfilerStubHelper.GetInstance = function()
+{
+    if (!ProfilerStubHelper.instance_)
+        ProfilerStubHelper.instance_ = new ProfilerStubHelper();
+    return ProfilerStubHelper.instance_;
+};
+
+
+ProfilerStubHelper.prototype.StopProfiling = function(modules)
+{
+    this.activeProfilerModules_ &= ~modules;
+};
+
+
+ProfilerStubHelper.prototype.StartProfiling = function(modules)
+{
+    var profModules = devtools.ProfilerAgent.ProfilerModules;
+    if (modules & profModules.PROFILER_MODULE_HEAP_SNAPSHOT) {
+        if (modules & profModules.PROFILER_MODULE_HEAP_STATS) {
+            this.log_ +=
+                'heap-sample-begin,"Heap","allocated",' +
+                    (new Date()).getTime() + '\n' +
+                'heap-sample-stats,"Heap","allocated",10000,1000\n';
+            this.log_ +=
+                'heap-sample-item,STRING_TYPE,100,1000\n' +
+                'heap-sample-item,CODE_TYPE,10,200\n' +
+                'heap-sample-item,MAP_TYPE,20,350\n';
+            this.log_ += ProfilerStubHelper.HeapSamples[this.heapProfSample_++];
+            this.heapProfSample_ %= ProfilerStubHelper.HeapSamples.length;
+            this.log_ += 'heap-sample-end,"Heap","allocated"\n';
+        }
+    } else {
+        if (modules & profModules.PROFILER_MODULE_CPU)
+            this.log_ += ProfilerStubHelper.ProfilerLogBuffer;
+        this.activeProfilerModules_ |= modules;
+    }
+};
+
+
+ProfilerStubHelper.prototype.getActiveProfilerModules = function()
+{
+    var self = this;
+    setTimeout(function() {
+        RemoteProfilerAgent.didGetActiveProfilerModules(self.activeProfilerModules_);
+    }, 100);
+};
+
+
+ProfilerStubHelper.prototype.getLogLines = function(pos)
+{
+    var profModules = devtools.ProfilerAgent.ProfilerModules;
+    var logLines = this.log_.substr(pos);
+    setTimeout(function() {
+        RemoteProfilerAgent.didGetLogLines(pos + logLines.length, logLines);
+    }, 100);
+};
+
+
+ProfilerStubHelper.ProfilerLogBuffer =
+    'profiler,begin,1\n' +
+    'profiler,resume\n' +
+    'code-creation,LazyCompile,0x1000,256,"test1 http://aaa.js:1"\n' +
+    'code-creation,LazyCompile,0x2000,256,"test2 http://bbb.js:2"\n' +
+    'code-creation,LazyCompile,0x3000,256,"test3 http://ccc.js:3"\n' +
+    'tick,0x1010,0x0,3\n' +
+    'tick,0x2020,0x0,3,0x1010\n' +
+    'tick,0x2020,0x0,3,0x1010\n' +
+    'tick,0x3010,0x0,3,0x2020, 0x1010\n' +
+    'tick,0x2020,0x0,3,0x1010\n' +
+    'tick,0x2030,0x0,3,0x2020, 0x1010\n' +
+    'tick,0x2020,0x0,3,0x1010\n' +
+    'tick,0x1010,0x0,3\n' +
+    'profiler,pause\n';
+
+
+ProfilerStubHelper.HeapSamples = [
+    'heap-js-cons-item,foo,1,100\n' +
+    'heap-js-cons-item,bar,20,2000\n' +
+    'heap-js-cons-item,Object,5,100\n' +
+    'heap-js-ret-item,foo,bar;3\n' +
+    'heap-js-ret-item,bar,foo;5\n' +
+    'heap-js-ret-item,Object:0x1234,(roots);1\n',
+
+    'heap-js-cons-item,foo,2000,200000\n' +
+    'heap-js-cons-item,bar,10,1000\n' +
+    'heap-js-cons-item,Object,6,120\n' +
+    'heap-js-ret-item,foo,bar;7,Object:0x1234;10\n' +
+    'heap-js-ret-item,bar,foo;10,Object:0x1234;10\n' +
+    'heap-js-ret-item,Object:0x1234,(roots);1\n',
+
+    'heap-js-cons-item,foo,15,1500\n' +
+    'heap-js-cons-item,bar,15,1500\n' +
+    'heap-js-cons-item,Object,5,100\n' +
+    'heap-js-cons-item,Array,3,1000\n' +
+    'heap-js-ret-item,foo,bar;3,Array:0x5678;1\n' +
+    'heap-js-ret-item,bar,foo;5,Object:0x1234;8,Object:0x5678;2\n' +
+    'heap-js-ret-item,Object:0x1234,(roots);1,Object:0x5678;2\n' +
+    'heap-js-ret-item,Object:0x5678,(global property);3,Object:0x1234;5\n' +
+    'heap-js-ret-item,Array:0x5678,(global property);3,Array:0x5678;2\n',
+
+    'heap-js-cons-item,bar,20,2000\n' +
+    'heap-js-cons-item,Object,6,120\n' +
+    'heap-js-ret-item,bar,foo;5,Object:0x1234;1,Object:0x1235;3\n' +
+    'heap-js-ret-item,Object:0x1234,(global property);3\n' +
+    'heap-js-ret-item,Object:0x1235,(global property);5\n',
+
+    'heap-js-cons-item,foo,15,1500\n' +
+    'heap-js-cons-item,bar,15,1500\n' +
+    'heap-js-cons-item,Array,10,1000\n' +
+    'heap-js-ret-item,foo,bar;1,Array:0x5678;1\n' +
+    'heap-js-ret-item,bar,foo;5\n' +
+    'heap-js-ret-item,Array:0x5678,(roots);3\n',
+
+    'heap-js-cons-item,bar,20,2000\n' +
+    'heap-js-cons-item,baz,15,1500\n' +
+    'heap-js-ret-item,bar,baz;3\n' +
+    'heap-js-ret-item,baz,bar;3\n'
+];
+
+
+/**
+ * @constructor
+ */
+RemoteDebuggerCommandExecutorStub = function()
+{
+};
+
+
+RemoteDebuggerCommandExecutorStub.prototype.DebuggerCommand = function(cmd)
+{
+    if ('{"seq":2,"type":"request","command":"scripts","arguments":{"includeSource":false}}' === cmd) {
+        var response1 =
+            '{"seq":5,"request_seq":2,"type":"response","command":"scripts","' +
+            'success":true,"body":[{"handle":61,"type":"script","name":"' +
+            'http://www/~test/t.js","id":59,"lineOffset":0,"columnOffset":0,' +
+            '"lineCount":1,"sourceStart":"function fib(n) {","sourceLength":300,' +
+            '"scriptType":2,"compilationType":0,"context":{"ref":60}}],"refs":[{' +
+            '"handle":60,"type":"context","data":"page,3"}],"running":false}';
+        this.sendResponse_(response1);
+    } else if ('{"seq":3,"type":"request","command":"scripts","arguments":{"ids":[59],"includeSource":true}}' === cmd) {
+        this.sendResponse_(
+            '{"seq":8,"request_seq":3,"type":"response","command":"scripts",' +
+            '"success":true,"body":[{"handle":1,"type":"script","name":' +
+            '"http://www/~test/t.js","id":59,"lineOffset":0,"columnOffset":0,' +
+            '"lineCount":1,"source":"function fib(n) {return n+1;}",' +
+            '"sourceLength":244,"scriptType":2,"compilationType":0,"context":{' +
+            '"ref":0}}],"refs":[{"handle":0,"type":"context","data":"page,3}],"' +
+            '"running":false}');
+    } else if (cmd.indexOf('"command":"profile"') !== -1) {
+        var cmdObj = JSON.parse(cmd);
+        if (cmdObj.arguments.command === "resume")
+            ProfilerStubHelper.GetInstance().StartProfiling(parseInt(cmdObj.arguments.modules));
+        else if (cmdObj.arguments.command === "pause")
+            ProfilerStubHelper.GetInstance().StopProfiling(parseInt(cmdObj.arguments.modules));
+        else
+            debugPrint("Unexpected profile command: " + cmdObj.arguments.command);
+    } else
+        debugPrint("Unexpected command: " + cmd);
+};
+
+
+RemoteDebuggerCommandExecutorStub.prototype.DebuggerPauseScript = function()
+{
+};
+
+
+RemoteDebuggerCommandExecutorStub.prototype.sendResponse_ = function(response)
+{
+    setTimeout(function() {
+        RemoteDebuggerAgent.debuggerOutput(response);
+    }, 0);
+};
+
+
+DevToolsHostStub = function()
+{
+    this.isStub = true;
+};
+DevToolsHostStub.prototype.__proto__ = WebInspector.InspectorFrontendHostStub.prototype;
+
+
+DevToolsHostStub.prototype.reset = function()
+{
+};
+
+
+DevToolsHostStub.prototype.setting = function()
+{
+};
+
+
+DevToolsHostStub.prototype.setSetting = function()
+{
+};
+
+
+window["RemoteDebuggerAgent"] = new RemoteDebuggerAgentStub();
+window["RemoteDebuggerCommandExecutor"] = new RemoteDebuggerCommandExecutorStub();
+window["RemoteProfilerAgent"] = new RemoteProfilerAgentStub();
+window["RemoteToolsAgent"] = new RemoteToolsAgentStub();
+InspectorFrontendHost = new DevToolsHostStub();
+
+}
diff --git a/WebKit/chromium/src/js/HeapProfilerPanel.js b/WebKit/chromium/src/js/HeapProfilerPanel.js
new file mode 100644
index 0000000..abbf580
--- /dev/null
+++ b/WebKit/chromium/src/js/HeapProfilerPanel.js
@@ -0,0 +1,966 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @fileoverview Heap profiler panel implementation.
+ */
+
+WebInspector.ProfilesPanel.prototype.addSnapshot = function(snapshot) {
+    snapshot.title = WebInspector.UIString("Snapshot %d", snapshot.number);
+    snapshot.typeId = WebInspector.HeapSnapshotProfileType.TypeId;
+
+    var snapshots = WebInspector.HeapSnapshotProfileType.snapshots;
+    snapshots.push(snapshot);
+
+    snapshot.listIndex = snapshots.length - 1;
+
+    if (WebInspector.CPUProfile)
+        this.addProfileHeader(WebInspector.HeapSnapshotProfileType.TypeId, snapshot);
+    else
+        this.addProfileHeader(snapshot);
+
+    this.dispatchEventToListeners("snapshot added");
+}
+
+
+WebInspector.HeapSnapshotView = function(parent, profile)
+{
+    WebInspector.View.call(this);
+
+    this.element.addStyleClass("heap-snapshot-view");
+
+    this.parent = parent;
+    this.parent.addEventListener("snapshot added", this._updateBaseOptions, this);
+
+    this.showCountAsPercent = false;
+    this.showSizeAsPercent = false;
+    this.showCountDeltaAsPercent = false;
+    this.showSizeDeltaAsPercent = false;
+
+    this.categories = {
+        code: new WebInspector.ResourceCategory("code", WebInspector.UIString("Code"), "rgb(255,121,0)"),
+        data: new WebInspector.ResourceCategory("data", WebInspector.UIString("Objects"), "rgb(47,102,236)")
+    };
+
+    var summaryContainer = document.createElement("div");
+    summaryContainer.id = "heap-snapshot-summary-container";
+
+    this.countsSummaryBar = new WebInspector.SummaryBar(this.categories);
+    this.countsSummaryBar.element.className = "heap-snapshot-summary";
+    this.countsSummaryBar.calculator = new WebInspector.HeapSummaryCountCalculator();
+    var countsLabel = document.createElement("div");
+    countsLabel.className = "heap-snapshot-summary-label";
+    countsLabel.textContent = WebInspector.UIString("Count");
+    this.countsSummaryBar.element.appendChild(countsLabel);
+    summaryContainer.appendChild(this.countsSummaryBar.element);
+
+    this.sizesSummaryBar = new WebInspector.SummaryBar(this.categories);
+    this.sizesSummaryBar.element.className = "heap-snapshot-summary";
+    this.sizesSummaryBar.calculator = new WebInspector.HeapSummarySizeCalculator();
+    var sizesLabel = document.createElement("label");
+    sizesLabel.className = "heap-snapshot-summary-label";
+    sizesLabel.textContent = WebInspector.UIString("Size");
+    this.sizesSummaryBar.element.appendChild(sizesLabel);
+    summaryContainer.appendChild(this.sizesSummaryBar.element);
+
+    this.element.appendChild(summaryContainer);
+
+    var columns = { "cons": { title: WebInspector.UIString("Constructor"), disclosure: true, sortable: true },
+                    "count": { title: WebInspector.UIString("Count"), width: "54px", sortable: true },
+                    "size": { title: WebInspector.UIString("Size"), width: "72px", sort: "descending", sortable: true },
+                    "countDelta": { title: WebInspector.UIString("\xb1 Count"), width: "72px", sortable: true },
+                    "sizeDelta": { title: WebInspector.UIString("\xb1 Size"), width: "72px", sortable: true } };
+
+    this.dataGrid = new WebInspector.DataGrid(columns);
+    this.dataGrid.addEventListener("sorting changed", this._sortData, this);
+    this.dataGrid.element.addEventListener("mousedown", this._mouseDownInDataGrid.bind(this), true);
+    this.element.appendChild(this.dataGrid.element);
+
+    this.profile = profile;
+
+    this.baseSelectElement = document.createElement("select");
+    this.baseSelectElement.className = "status-bar-item";
+    this.baseSelectElement.addEventListener("change", this._changeBase.bind(this), false);
+    this._updateBaseOptions();
+    if (this.profile.listIndex > 0)
+        this.baseSelectElement.selectedIndex = this.profile.listIndex - 1;
+    else
+        this.baseSelectElement.selectedIndex = this.profile.listIndex;
+    this._resetDataGridList();
+
+    this.percentButton = new WebInspector.StatusBarButton("", "percent-time-status-bar-item status-bar-item");
+    this.percentButton.addEventListener("click", this._percentClicked.bind(this), false);
+
+    this.refresh();
+
+    this._updatePercentButton();
+};
+
+WebInspector.HeapSnapshotView.prototype = {
+
+    get statusBarItems()
+    {
+        return [this.baseSelectElement, this.percentButton.element];
+    },
+
+    get profile()
+    {
+        return this._profile;
+    },
+
+    set profile(profile)
+    {
+        this._profile = profile;
+    },
+
+    show: function(parentElement)
+    {
+        WebInspector.View.prototype.show.call(this, parentElement);
+        this.dataGrid.updateWidths();
+    },
+
+    hide: function()
+    {
+        WebInspector.View.prototype.hide.call(this);
+        this._currentSearchResultIndex = -1;
+    },
+
+    resize: function()
+    {
+        if (this.dataGrid)
+            this.dataGrid.updateWidths();
+    },
+
+    refresh: function()
+    {
+        this.dataGrid.removeChildren();
+
+        var children = this.snapshotDataGridList.children;
+        var count = children.length;
+        for (var index = 0; index < count; ++index)
+            this.dataGrid.appendChild(children[index]);
+
+        this._updateSummaryGraph();
+    },
+
+    refreshShowAsPercents: function()
+    {
+        this._updatePercentButton();
+        this.refreshVisibleData();
+    },
+
+    _deleteSearchMatchedFlags: function(node)
+    {
+        delete node._searchMatchedConsColumn;
+        delete node._searchMatchedCountColumn;
+        delete node._searchMatchedSizeColumn;
+        delete node._searchMatchedCountDeltaColumn;
+        delete node._searchMatchedSizeDeltaColumn;
+    },
+
+    searchCanceled: function()
+    {
+        if (this._searchResults) {
+            for (var i = 0; i < this._searchResults.length; ++i) {
+                var profileNode = this._searchResults[i].profileNode;
+                this._deleteSearchMatchedFlags(profileNode);
+                profileNode.refresh();
+            }
+        }
+
+        delete this._searchFinishedCallback;
+        this._currentSearchResultIndex = -1;
+        this._searchResults = [];
+    },
+
+    performSearch: function(query, finishedCallback)
+    {
+        // Call searchCanceled since it will reset everything we need before doing a new search.
+        this.searchCanceled();
+
+        query = query.trimWhitespace();
+
+        if (!query.length)
+            return;
+
+        this._searchFinishedCallback = finishedCallback;
+
+        var helper = WebInspector.HeapSnapshotView.SearchHelper;
+
+        var operationAndNumber = helper.parseOperationAndNumber(query);
+        var operation = operationAndNumber[0];
+        var queryNumber = operationAndNumber[1];
+
+        var percentUnits = helper.percents.test(query);
+        var megaBytesUnits = helper.megaBytes.test(query);
+        var kiloBytesUnits = helper.kiloBytes.test(query);
+        var bytesUnits = helper.bytes.test(query);
+
+        var queryNumberBytes = (megaBytesUnits ? (queryNumber * 1024 * 1024) : (kiloBytesUnits ? (queryNumber * 1024) : queryNumber));
+
+        function matchesQuery(heapSnapshotDataGridNode)
+        {
+            WebInspector.HeapSnapshotView.prototype._deleteSearchMatchedFlags(heapSnapshotDataGridNode);
+
+            if (percentUnits) {
+                heapSnapshotDataGridNode._searchMatchedCountColumn = operation(heapSnapshotDataGridNode.countPercent, queryNumber);
+                heapSnapshotDataGridNode._searchMatchedSizeColumn = operation(heapSnapshotDataGridNode.sizePercent, queryNumber);
+                heapSnapshotDataGridNode._searchMatchedCountDeltaColumn = operation(heapSnapshotDataGridNode.countDeltaPercent, queryNumber);
+                heapSnapshotDataGridNode._searchMatchedSizeDeltaColumn = operation(heapSnapshotDataGridNode.sizeDeltaPercent, queryNumber);
+            } else if (megaBytesUnits || kiloBytesUnits || bytesUnits) {
+                heapSnapshotDataGridNode._searchMatchedSizeColumn = operation(heapSnapshotDataGridNode.size, queryNumberBytes);
+                heapSnapshotDataGridNode._searchMatchedSizeDeltaColumn = operation(heapSnapshotDataGridNode.sizeDelta, queryNumberBytes);
+            } else {
+                heapSnapshotDataGridNode._searchMatchedCountColumn = operation(heapSnapshotDataGridNode.count, queryNumber);
+                heapSnapshotDataGridNode._searchMatchedCountDeltaColumn = operation(heapSnapshotDataGridNode.countDelta, queryNumber);
+            }
+
+            if (heapSnapshotDataGridNode.constructorName.hasSubstring(query, true))
+                heapSnapshotDataGridNode._searchMatchedConsColumn = true;
+
+            if (heapSnapshotDataGridNode._searchMatchedConsColumn ||
+                heapSnapshotDataGridNode._searchMatchedCountColumn ||
+                heapSnapshotDataGridNode._searchMatchedSizeColumn ||
+                heapSnapshotDataGridNode._searchMatchedCountDeltaColumn ||
+                heapSnapshotDataGridNode._searchMatchedSizeDeltaColumn) {
+                heapSnapshotDataGridNode.refresh();
+                return true;
+            }
+
+            return false;
+        }
+
+        var current = this.snapshotDataGridList.children[0];
+        var depth = 0;
+        var info = {};
+
+        // The second and subsequent levels of heap snapshot nodes represent retainers,
+        // so recursive expansion will be infinite, since a graph is being traversed.
+        // So default to a recursion cap of 2 levels.
+        var maxDepth = 2;
+
+        while (current) {
+            if (matchesQuery(current))
+                this._searchResults.push({ profileNode: current });
+            current = current.traverseNextNode(false, null, (depth >= maxDepth), info);
+            depth += info.depthChange;
+        }
+
+        finishedCallback(this, this._searchResults.length);
+    },
+
+    jumpToFirstSearchResult: WebInspector.CPUProfileView.prototype.jumpToFirstSearchResult,
+    jumpToLastSearchResult: WebInspector.CPUProfileView.prototype.jumpToLastSearchResult,
+    jumpToNextSearchResult: WebInspector.CPUProfileView.prototype.jumpToNextSearchResult,
+    jumpToPreviousSearchResult: WebInspector.CPUProfileView.prototype.jumpToPreviousSearchResult,
+    showingFirstSearchResult: WebInspector.CPUProfileView.prototype.showingFirstSearchResult,
+    showingLastSearchResult: WebInspector.CPUProfileView.prototype.showingLastSearchResult,
+    _jumpToSearchResult: WebInspector.CPUProfileView.prototype._jumpToSearchResult,
+
+    refreshVisibleData: function()
+    {
+        var child = this.dataGrid.children[0];
+        while (child) {
+            child.refresh();
+            child = child.traverseNextNode(false, null, true);
+        }
+        this._updateSummaryGraph();
+    },
+
+    _changeBase: function() {
+        if (this.baseSnapshot === WebInspector.HeapSnapshotProfileType.snapshots[this.baseSelectElement.selectedIndex])
+            return;
+
+        this._resetDataGridList();
+        this.refresh();
+
+        if (!this.currentQuery || !this._searchFinishedCallback || !this._searchResults)
+            return;
+
+        // The current search needs to be performed again. First negate out previous match
+        // count by calling the search finished callback with a negative number of matches.
+        // Then perform the search again with the same query and callback.
+        this._searchFinishedCallback(this, -this._searchResults.length);
+        this.performSearch(this.currentQuery, this._searchFinishedCallback);
+    },
+
+    _createSnapshotDataGridList: function()
+    {
+        if (this._snapshotDataGridList)
+          delete this._snapshotDataGridList;
+
+        this._snapshotDataGridList = new WebInspector.HeapSnapshotDataGridList(this, this.baseSnapshot.entries, this.profile.entries);
+        return this._snapshotDataGridList;
+    },
+
+    _mouseDownInDataGrid: function(event)
+    {
+        if (event.detail < 2)
+            return;
+
+        var cell = event.target.enclosingNodeOrSelfWithNodeName("td");
+        if (!cell || (!cell.hasStyleClass("count-column") && !cell.hasStyleClass("size-column") && !cell.hasStyleClass("countDelta-column") && !cell.hasStyleClass("sizeDelta-column")))
+            return;
+
+        if (cell.hasStyleClass("count-column"))
+            this.showCountAsPercent = !this.showCountAsPercent;
+        else if (cell.hasStyleClass("size-column"))
+            this.showSizeAsPercent = !this.showSizeAsPercent;
+        else if (cell.hasStyleClass("countDelta-column"))
+            this.showCountDeltaAsPercent = !this.showCountDeltaAsPercent;
+        else if (cell.hasStyleClass("sizeDelta-column"))
+            this.showSizeDeltaAsPercent = !this.showSizeDeltaAsPercent;
+
+        this.refreshShowAsPercents();
+
+        event.preventDefault();
+        event.stopPropagation();
+    },
+
+    get _isShowingAsPercent()
+    {
+        return this.showCountAsPercent && this.showSizeAsPercent && this.showCountDeltaAsPercent && this.showSizeDeltaAsPercent;
+    },
+
+    _percentClicked: function(event)
+    {
+        var currentState = this._isShowingAsPercent;
+        this.showCountAsPercent = !currentState;
+        this.showSizeAsPercent = !currentState;
+        this.showCountDeltaAsPercent = !currentState;
+        this.showSizeDeltaAsPercent = !currentState;
+        this.refreshShowAsPercents();
+    },
+
+    _resetDataGridList: function()
+    {
+        this.baseSnapshot = WebInspector.HeapSnapshotProfileType.snapshots[this.baseSelectElement.selectedIndex];
+        var lastComparator = WebInspector.HeapSnapshotDataGridList.propertyComparator("size", false);
+        if (this.snapshotDataGridList)
+            lastComparator = this.snapshotDataGridList.lastComparator;
+        this.snapshotDataGridList = this._createSnapshotDataGridList();
+        this.snapshotDataGridList.sort(lastComparator, true);
+    },
+
+    _sortData: function()
+    {
+        var sortAscending = this.dataGrid.sortOrder === "ascending";
+        var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier;
+        var sortProperty = {
+                "cons": ["constructorName", null],
+                "count": ["count", null],
+                "size": ["size", "count"],
+                "countDelta": this.showCountDeltaAsPercent ? ["countDeltaPercent", null] : ["countDelta", null],
+                "sizeDelta": this.showSizeDeltaAsPercent ? ["sizeDeltaPercent", "countDeltaPercent"] : ["sizeDelta", "sizeDeltaPercent"]
+        }[sortColumnIdentifier];
+
+        this.snapshotDataGridList.sort(WebInspector.HeapSnapshotDataGridList.propertyComparator(sortProperty[0], sortProperty[1], sortAscending));
+
+        this.refresh();
+    },
+
+    _updateBaseOptions: function()
+    {
+        var list = WebInspector.HeapSnapshotProfileType.snapshots;
+        // We're assuming that snapshots can only be added.
+        if (this.baseSelectElement.length === list.length)
+            return;
+
+        for (var i = this.baseSelectElement.length, n = list.length; i < n; ++i) {
+            var baseOption = document.createElement("option");
+            baseOption.label = WebInspector.UIString("Compared to %s", list[i].title);
+            this.baseSelectElement.appendChild(baseOption);
+        }
+    },
+
+    _updatePercentButton: function()
+    {
+        if (this._isShowingAsPercent) {
+            this.percentButton.title = WebInspector.UIString("Show absolute counts and sizes.");
+            this.percentButton.toggled = true;
+        } else {
+            this.percentButton.title = WebInspector.UIString("Show counts and sizes as percentages.");
+            this.percentButton.toggled = false;
+        }
+    },
+
+    _updateSummaryGraph: function()
+    {
+        this.countsSummaryBar.calculator.showAsPercent = this._isShowingAsPercent;
+        this.countsSummaryBar.update(this.profile.lowlevels);
+
+        this.sizesSummaryBar.calculator.showAsPercent = this._isShowingAsPercent;
+        this.sizesSummaryBar.update(this.profile.lowlevels);
+    }
+};
+
+WebInspector.HeapSnapshotView.prototype.__proto__ = WebInspector.View.prototype;
+
+WebInspector.HeapSnapshotView.SearchHelper = {
+    // In comparators, we assume that a value from a node is passed as the first parameter.
+    operations: { LESS: function (a, b) { return a !== null && a < b; },
+                  LESS_OR_EQUAL: function (a, b) { return a !== null && a <= b; },
+                  EQUAL: function (a, b) { return a !== null && a === b; },
+                  GREATER_OR_EQUAL: function (a, b) { return a !== null && a >= b; },
+                  GREATER: function (a, b) { return a !== null && a > b; } },
+
+    operationParsers: { LESS: /^<(\d+)/,
+                        LESS_OR_EQUAL: /^<=(\d+)/,
+                        GREATER_OR_EQUAL: /^>=(\d+)/,
+                        GREATER: /^>(\d+)/ },
+
+    parseOperationAndNumber: function(query)
+    {
+        var operations = WebInspector.HeapSnapshotView.SearchHelper.operations;
+        var parsers = WebInspector.HeapSnapshotView.SearchHelper.operationParsers;
+        for (var operation in parsers) {
+            var match = query.match(parsers[operation]);
+            if (match !== null)
+                return [operations[operation], parseFloat(match[1])];
+        }
+        return [operations.EQUAL, parseFloat(query)];
+    },
+
+    percents: /%$/,
+
+    megaBytes: /MB$/i,
+
+    kiloBytes: /KB$/i,
+
+    bytes: /B$/i
+}
+
+WebInspector.HeapSummaryCalculator = function(lowLevelField)
+{
+    this.total = 1;
+    this.lowLevelField = lowLevelField;
+}
+
+WebInspector.HeapSummaryCalculator.prototype = {
+    computeSummaryValues: function(lowLevels)
+    {
+        var highLevels = {data: 0, code: 0};
+        this.total = 0;
+        for (var item in lowLevels) {
+            var highItem = this._highFromLow(item);
+            if (highItem) {
+                var value = lowLevels[item][this.lowLevelField];
+                highLevels[highItem] += value;
+                this.total += value;
+            }
+        }
+        var result = {categoryValues: highLevels};
+        if (!this.showAsPercent)
+            result.total = this.total;
+        return result;
+    },
+
+    formatValue: function(value)
+    {
+        if (this.showAsPercent)
+            return WebInspector.UIString("%.2f%%", value / this.total * 100.0);
+        else
+            return this._valueToString(value);
+    },
+
+    get showAsPercent()
+    {
+        return this._showAsPercent;
+    },
+
+    set showAsPercent(x)
+    {
+        this._showAsPercent = x;
+    }
+}
+
+WebInspector.HeapSummaryCountCalculator = function()
+{
+    WebInspector.HeapSummaryCalculator.call(this, "count");
+}
+
+WebInspector.HeapSummaryCountCalculator.prototype = {
+    _highFromLow: function(type) {
+        if (type === "CODE_TYPE" || type === "SHARED_FUNCTION_INFO_TYPE" || type === "SCRIPT_TYPE") return "code";
+        if (type === "STRING_TYPE" || type === "HEAP_NUMBER_TYPE" || type.match(/^JS_/)) return "data";
+        return null;
+    },
+
+    _valueToString: function(value) {
+        return value.toString();
+    }
+}
+
+WebInspector.HeapSummaryCountCalculator.prototype.__proto__ = WebInspector.HeapSummaryCalculator.prototype;
+
+WebInspector.HeapSummarySizeCalculator = function()
+{
+    WebInspector.HeapSummaryCalculator.call(this, "size");
+}
+
+WebInspector.HeapSummarySizeCalculator.prototype = {
+    _highFromLow: function(type) {
+        if (type === "CODE_TYPE" || type === "SHARED_FUNCTION_INFO_TYPE" || type === "SCRIPT_TYPE") return "code";
+        if (type === "STRING_TYPE" || type === "HEAP_NUMBER_TYPE" || type.match(/^JS_/) || type.match(/_ARRAY_TYPE$/)) return "data";
+        return null;
+    },
+
+    _valueToString: Number.bytesToString
+}
+
+WebInspector.HeapSummarySizeCalculator.prototype.__proto__ = WebInspector.HeapSummaryCalculator.prototype;
+
+WebInspector.HeapSnapshotSidebarTreeElement = function(snapshot)
+{
+    this.profile = snapshot;
+
+    WebInspector.SidebarTreeElement.call(this, "heap-snapshot-sidebar-tree-item", "", "", snapshot, false);
+
+    this.refreshTitles();
+};
+
+WebInspector.HeapSnapshotSidebarTreeElement.prototype = {
+    get mainTitle()
+    {
+        if (this._mainTitle)
+            return this._mainTitle;
+        return this.profile.title;
+    },
+
+    set mainTitle(x)
+    {
+        this._mainTitle = x;
+        this.refreshTitles();
+    }
+};
+
+WebInspector.HeapSnapshotSidebarTreeElement.prototype.__proto__ = WebInspector.ProfileSidebarTreeElement.prototype;
+
+WebInspector.HeapSnapshotDataGridNodeWithRetainers = function(owningTree)
+{
+    this.tree = owningTree;
+
+    WebInspector.DataGridNode.call(this, null, this._hasRetainers);
+
+    this.addEventListener("populate", this._populate, this);
+};
+
+WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype = {
+    isEmptySet: function(set)
+    {
+        for (var x in set)
+            return false;
+        return true;
+    },
+
+    get _hasRetainers()
+    {
+        return !this.isEmptySet(this.retainers);
+    },
+
+    get _parent()
+    {
+        // For top-level nodes, return owning tree as a parent, not data grid.
+        return this.parent !== this.dataGrid ? this.parent : this.tree;
+    },
+
+    _populate: function(event)
+    {
+        var self = this;
+        this.produceDiff(this.baseRetainers, this.retainers, function(baseItem, snapshotItem) {
+            self.appendChild(new WebInspector.HeapSnapshotDataGridRetainerNode(self.snapshotView, baseItem, snapshotItem, self.tree));
+        });
+
+        if (this._parent) {
+            var currentComparator = this._parent.lastComparator;
+            if (currentComparator)
+                this.sort(currentComparator, true);
+        }
+
+        this.removeEventListener("populate", this._populate, this);
+    },
+
+    produceDiff: function(baseEntries, currentEntries, callback)
+    {
+        for (var item in currentEntries)
+            callback(baseEntries[item], currentEntries[item]);
+
+        for (item in baseEntries) {
+            if (!(item in currentEntries))
+                callback(baseEntries[item], null);
+        }
+    },
+
+    sort: function(comparator, force) {
+        if (!force && this.lastComparator === comparator)
+            return;
+
+        this.children.sort(comparator);
+        var childCount = this.children.length;
+        for (var childIndex = 0; childIndex < childCount; ++childIndex)
+            this.children[childIndex]._recalculateSiblings(childIndex);
+        for (var i = 0; i < this.children.length; ++i) {
+            var child = this.children[i];
+            if (!force && (!child.expanded || child.lastComparator === comparator))
+                continue;
+            child.sort(comparator, force);
+        }
+        this.lastComparator = comparator;
+    },
+
+    signForDelta: function(delta) {
+        if (delta === 0)
+            return "";
+        if (delta > 0)
+            return "+";
+        else
+            // Math minus sign, same width as plus.
+            return "\u2212";
+    },
+
+    showDeltaAsPercent: function(value) {
+        if (value === Number.POSITIVE_INFINITY)
+            return WebInspector.UIString("new");
+        else if (value === Number.NEGATIVE_INFINITY)
+            return WebInspector.UIString("deleted");
+        if (value > 1000.0)
+            return WebInspector.UIString("%s >1000%%", this.signForDelta(value));
+        return WebInspector.UIString("%s%.2f%%", this.signForDelta(value), Math.abs(value));
+    },
+
+    getTotalCount: function() {
+        if (!this._count) {
+            this._count = 0;
+            for (var i = 0, n = this.children.length; i < n; ++i)
+                this._count += this.children[i].count;
+        }
+        return this._count;
+    },
+
+    getTotalSize: function() {
+        if (!this._size) {
+            this._size = 0;
+            for (var i = 0, n = this.children.length; i < n; ++i)
+                this._size += this.children[i].size;
+        }
+        return this._size;
+    },
+
+    get countPercent()
+    {
+        return this.count / this._parent.getTotalCount() * 100.0;
+    },
+
+    get sizePercent()
+    {
+        return this.size / this._parent.getTotalSize() * 100.0;
+    },
+
+    get countDeltaPercent()
+    {
+        if (this.baseCount > 0) {
+            if (this.count > 0)
+                return this.countDelta / this.baseCount * 100.0;
+            else
+                return Number.NEGATIVE_INFINITY;
+        } else
+            return Number.POSITIVE_INFINITY;
+    },
+
+    get sizeDeltaPercent()
+    {
+        if (this.baseSize > 0) {
+            if (this.size > 0)
+                return this.sizeDelta / this.baseSize * 100.0;
+            else
+                return Number.NEGATIVE_INFINITY;
+        } else
+            return Number.POSITIVE_INFINITY;
+    },
+
+    get data()
+    {
+        var data = {};
+
+        data["cons"] = this.constructorName;
+
+        if (this.snapshotView.showCountAsPercent)
+            data["count"] = WebInspector.UIString("%.2f%%", this.countPercent);
+        else
+            data["count"] = this.count;
+
+        if (this.size !== null) {
+            if (this.snapshotView.showSizeAsPercent)
+                data["size"] = WebInspector.UIString("%.2f%%", this.sizePercent);
+            else
+                data["size"] = Number.bytesToString(this.size);
+        } else
+            data["size"] = "";
+
+        if (this.snapshotView.showCountDeltaAsPercent)
+            data["countDelta"] = this.showDeltaAsPercent(this.countDeltaPercent);
+        else
+            data["countDelta"] = WebInspector.UIString("%s%d", this.signForDelta(this.countDelta), Math.abs(this.countDelta));
+
+        if (this.sizeDelta !== null) {
+            if (this.snapshotView.showSizeDeltaAsPercent)
+                data["sizeDelta"] = this.showDeltaAsPercent(this.sizeDeltaPercent);
+            else
+                data["sizeDelta"] = WebInspector.UIString("%s%s", this.signForDelta(this.sizeDelta), Number.bytesToString(Math.abs(this.sizeDelta)));
+        } else
+            data["sizeDelta"] = "";
+
+        return data;
+    },
+
+    createCell: function(columnIdentifier)
+    {
+        var cell = WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier);
+
+        if ((columnIdentifier === "cons" && this._searchMatchedConsColumn) ||
+            (columnIdentifier === "count" && this._searchMatchedCountColumn) ||
+            (columnIdentifier === "size" && this._searchMatchedSizeColumn) ||
+            (columnIdentifier === "countDelta" && this._searchMatchedCountDeltaColumn) ||
+            (columnIdentifier === "sizeDelta" && this._searchMatchedSizeDeltaColumn))
+            cell.addStyleClass("highlight");
+
+        return cell;
+    }
+};
+
+WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.__proto__ = WebInspector.DataGridNode.prototype;
+
+WebInspector.HeapSnapshotDataGridNode = function(snapshotView, baseEntry, snapshotEntry, owningTree)
+{
+    this.snapshotView = snapshotView;
+
+    if (!snapshotEntry)
+        snapshotEntry = { cons: baseEntry.cons, count: 0, size: 0, retainers: {} };
+    this.constructorName = snapshotEntry.cons;
+    this.count = snapshotEntry.count;
+    this.size = snapshotEntry.size;
+    this.retainers = snapshotEntry.retainers;
+
+    if (!baseEntry)
+        baseEntry = { count: 0, size: 0, retainers: {} };
+    this.baseCount = baseEntry.count;
+    this.countDelta = this.count - this.baseCount;
+    this.baseSize = baseEntry.size;
+    this.sizeDelta = this.size - this.baseSize;
+    this.baseRetainers = baseEntry.retainers;
+
+    WebInspector.HeapSnapshotDataGridNodeWithRetainers.call(this, owningTree);
+};
+
+WebInspector.HeapSnapshotDataGridNode.prototype.__proto__ = WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype;
+
+WebInspector.HeapSnapshotDataGridList = function(snapshotView, baseEntries, snapshotEntries)
+{
+    this.tree = this;
+    this.snapshotView = snapshotView;
+    this.children = [];
+    this.lastComparator = null;
+    this.populateChildren(baseEntries, snapshotEntries);
+};
+
+WebInspector.HeapSnapshotDataGridList.prototype = {
+    appendChild: function(child)
+    {
+        this.insertChild(child, this.children.length);
+    },
+
+    insertChild: function(child, index)
+    {
+        this.children.splice(index, 0, child);
+    },
+
+    removeChildren: function()
+    {
+        this.children = [];
+    },
+
+    populateChildren: function(baseEntries, snapshotEntries)
+    {
+        var self = this;
+        this.produceDiff(baseEntries, snapshotEntries, function(baseItem, snapshotItem) {
+            self.appendChild(new WebInspector.HeapSnapshotDataGridNode(self.snapshotView, baseItem, snapshotItem, self));
+        });
+    },
+
+    produceDiff: WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.produceDiff,
+    sort: WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.sort,
+    getTotalCount: WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.getTotalCount,
+    getTotalSize: WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.getTotalSize
+};
+
+WebInspector.HeapSnapshotDataGridList.propertyComparators = [{}, {}];
+
+WebInspector.HeapSnapshotDataGridList.propertyComparator = function(property, property2, isAscending)
+{
+    var propertyHash = property + "#" + property2;
+    var comparator = this.propertyComparators[(isAscending ? 1 : 0)][propertyHash];
+    if (!comparator) {
+        comparator = function(lhs, rhs) {
+            var l = lhs[property], r = rhs[property];
+            if ((l === null || r === null) && property2 !== null)
+                l = lhs[property2], r = rhs[property2];
+            var result = l < r ? -1 : (l > r ? 1 : 0);
+            return isAscending ? result : -result;
+        };
+        this.propertyComparators[(isAscending ? 1 : 0)][propertyHash] = comparator;
+    }
+    return comparator;
+};
+
+WebInspector.HeapSnapshotDataGridRetainerNode = function(snapshotView, baseEntry, snapshotEntry, owningTree)
+{
+    this.snapshotView = snapshotView;
+
+    if (!snapshotEntry)
+        snapshotEntry = { cons: baseEntry.cons, count: 0, clusters: {} };
+    this.constructorName = snapshotEntry.cons;
+    this.count = snapshotEntry.count;
+    this.retainers = this._calculateRetainers(this.snapshotView.profile, snapshotEntry.clusters);
+
+    if (!baseEntry)
+        baseEntry = { count: 0, clusters: {} };
+    this.baseCount = baseEntry.count;
+    this.countDelta = this.count - this.baseCount;
+    this.baseRetainers = this._calculateRetainers(this.snapshotView.baseSnapshot, baseEntry.clusters);
+
+    this.size = null;
+    this.sizeDelta = null;
+
+    WebInspector.HeapSnapshotDataGridNodeWithRetainers.call(this, owningTree);
+}
+
+WebInspector.HeapSnapshotDataGridRetainerNode.prototype = {
+    get sizePercent()
+    {
+        return null;
+    },
+
+    get sizeDeltaPercent()
+    {
+        return null;
+    },
+
+    _calculateRetainers: function(snapshot, clusters) {
+        var retainers = {};
+        if (this.isEmptySet(clusters)) {
+            if (this.constructorName in snapshot.entries)
+                return snapshot.entries[this.constructorName].retainers;
+        } else {
+            // In case when an entry is retained by clusters, we need to gather up the list
+            // of retainers by merging retainers of every cluster.
+            // E.g. having such a tree:
+            //   A
+            //     Object:1  10
+            //       X       3
+            //       Y       4
+            //     Object:2  5
+            //       X       6
+            //
+            // will result in a following retainers list: X 9, Y 4.
+            for (var clusterName in clusters) {
+                if (clusterName in snapshot.clusters) {
+                    var clusterRetainers = snapshot.clusters[clusterName].retainers;
+                    for (var clusterRetainer in clusterRetainers) {
+                        var clusterRetainerEntry = clusterRetainers[clusterRetainer];
+                        if (!(clusterRetainer in retainers))
+                            retainers[clusterRetainer] = { cons: clusterRetainerEntry.cons, count: 0, clusters: {} };
+                        retainers[clusterRetainer].count += clusterRetainerEntry.count;
+                        for (var clusterRetainerCluster in clusterRetainerEntry.clusters)
+                            retainers[clusterRetainer].clusters[clusterRetainerCluster] = true;
+                    }
+                }
+            }
+        }
+        return retainers;
+    }
+};
+
+WebInspector.HeapSnapshotDataGridRetainerNode.prototype.__proto__ = WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype;
+
+
+WebInspector.HeapSnapshotProfileType = function()
+{
+    WebInspector.ProfileType.call(this, WebInspector.HeapSnapshotProfileType.TypeId, WebInspector.UIString("HEAP SNAPSHOTS"));
+}
+
+WebInspector.HeapSnapshotProfileType.TypeId = "HEAP";
+
+WebInspector.HeapSnapshotProfileType.snapshots = [];
+
+WebInspector.HeapSnapshotProfileType.prototype = {
+    get buttonTooltip()
+    {
+        return WebInspector.UIString("Take heap snapshot.");
+    },
+
+    get buttonStyle()
+    {
+        return "heap-snapshot-status-bar-item status-bar-item";
+    },
+
+    buttonClicked: function()
+    {
+        InspectorBackend.takeHeapSnapshot();
+    },
+
+    get welcomeMessage()
+    {
+        return WebInspector.UIString("Get a heap snapshot by pressing<br>the %s button on the status bar.");
+    },
+
+    createSidebarTreeElementForProfile: function(profile)
+    {
+        var element = new WebInspector.HeapSnapshotSidebarTreeElement(profile);
+        element.small = false;
+        return element;
+    },
+
+    createView: function(profile)
+    {
+        return new WebInspector.HeapSnapshotView(WebInspector.panels.profiles, profile);
+    }
+}
+
+WebInspector.HeapSnapshotProfileType.prototype.__proto__ = WebInspector.ProfileType.prototype;
+
+
+(function() {
+    var originalCreatePanels = WebInspector._createPanels;
+    WebInspector._createPanels = function() {
+        originalCreatePanels.apply(this, arguments);
+        if (WebInspector.panels.profiles)
+            WebInspector.panels.profiles.registerProfileType(new WebInspector.HeapSnapshotProfileType());
+    }
+})();
diff --git a/WebKit/chromium/src/js/InjectDispatch.js b/WebKit/chromium/src/js/InjectDispatch.js
new file mode 100644
index 0000000..1c2cba2
--- /dev/null
+++ b/WebKit/chromium/src/js/InjectDispatch.js
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @fileoverview Injects "injected" object into the inspectable page.
+ */
+
+
+var InspectorControllerDispatcher = {};
+
+/**
+ * Main dispatch method, all calls from the host to InspectorController go
+ * through this one.
+ * @param {string} functionName Function to call
+ * @param {string} json_args JSON-serialized call parameters.
+ * @return {string} JSON-serialized result of the dispatched call.
+ */
+InspectorControllerDispatcher.dispatch = function(functionName, json_args)
+{
+    var params = JSON.parse(json_args);
+    InspectorBackend[functionName].apply(InspectorBackend, params);
+};
+
+/**
+ * Special controller object for APU related messages. Outgoing messages
+ * are sent to this object if the ApuAgentDispatcher is enabled.
+ **/
+var ApuAgentDispatcher = { enabled : false };
+
+/**
+ * Dispatches messages to APU. This filters and transforms
+ * outgoing messages that are used by APU.
+ * @param {string} method name of the dispatch method.
+ **/
+ApuAgentDispatcher.dispatchToApu = function(method, args)
+{
+    if (method !== "addRecordToTimeline" && method !== "updateResource" && method !== "addResource")
+        return;
+    // TODO(knorton): Transform args so they can be used
+    // by APU.
+    DevToolsAgentHost.dispatchToApu(JSON.stringify(args));
+};
+
+/**
+ * This is called by the InspectorFrontend for serialization.
+ * We serialize the call and send it to the client over the IPC
+ * using dispatchOut bound method.
+ */
+function dispatch(method, var_args) {
+    // Handle all messages with non-primitieve arguments here.
+    var args = Array.prototype.slice.call(arguments);
+
+    if (method === "inspectedWindowCleared" || method === "reset" || method === "setAttachedWindow") {
+        // Filter out messages we don't need here.
+        // We do it on the sender side since they may have non-serializable
+        // parameters.
+        return;
+    }
+
+    // Sniff some inspector controller state changes in order to support
+    // cross-navigation instrumentation. Keep names in sync with
+    // webdevtoolsagent_impl.
+    if (method === "timelineProfilerWasStarted")
+        DevToolsAgentHost.runtimeFeatureStateChanged("timeline-profiler", true);
+    else if (method === "timelineProfilerWasStopped")
+        DevToolsAgentHost.runtimeFeatureStateChanged("timeline-profiler", false);
+    else if (method === "resourceTrackingWasEnabled")
+        DevToolsAgentHost.runtimeFeatureStateChanged("resource-tracking", true);
+    else if (method === "resourceTrackingWasDisabled")
+        DevToolsAgentHost.runtimeFeatureStateChanged("resource-tracking", false);
+
+    if (ApuAgentDispatcher.enabled) {
+        ApuAgentDispatcher.dispatchToApu(method, args);
+        return;
+    }
+
+    var call = JSON.stringify(args);
+    DevToolsAgentHost.dispatch(call);
+};
+
+/**
+ * A no-op function that is called by debugger agent just to trigger v8
+ * execution.
+ */
+function devtools$$void() {
+}
diff --git a/WebKit/chromium/src/js/InspectorControllerImpl.js b/WebKit/chromium/src/js/InspectorControllerImpl.js
new file mode 100644
index 0000000..c92a94c
--- /dev/null
+++ b/WebKit/chromium/src/js/InspectorControllerImpl.js
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @fileoverview DevTools' implementation of the InspectorController API.
+ */
+
+if (!this.devtools)
+    devtools = {};
+
+devtools.InspectorBackendImpl = function()
+{
+    WebInspector.InspectorBackendStub.call(this);
+    this.installInspectorControllerDelegate_("clearMessages");
+    this.installInspectorControllerDelegate_("copyNode");
+    this.installInspectorControllerDelegate_("deleteCookie");
+    this.installInspectorControllerDelegate_("didEvaluateForTestInFrontend");
+    this.installInspectorControllerDelegate_("disableResourceTracking");
+    this.installInspectorControllerDelegate_("disableTimeline");
+    this.installInspectorControllerDelegate_("enableResourceTracking");
+    this.installInspectorControllerDelegate_("enableTimeline");
+    this.installInspectorControllerDelegate_("getChildNodes");
+    this.installInspectorControllerDelegate_("getCookies");
+    this.installInspectorControllerDelegate_("getDatabaseTableNames");
+    this.installInspectorControllerDelegate_("getDOMStorageEntries");
+    this.installInspectorControllerDelegate_("getEventListenersForNode");
+    this.installInspectorControllerDelegate_("getResourceContent");
+    this.installInspectorControllerDelegate_("highlightDOMNode");
+    this.installInspectorControllerDelegate_("hideDOMNodeHighlight");
+    this.installInspectorControllerDelegate_("releaseWrapperObjectGroup");
+    this.installInspectorControllerDelegate_("removeAttribute");
+    this.installInspectorControllerDelegate_("removeDOMStorageItem");
+    this.installInspectorControllerDelegate_("removeNode");
+    this.installInspectorControllerDelegate_("saveFrontendSettings");
+    this.installInspectorControllerDelegate_("setAttribute");
+    this.installInspectorControllerDelegate_("setDOMStorageItem");
+    this.installInspectorControllerDelegate_("setInjectedScriptSource");
+    this.installInspectorControllerDelegate_("setTextNodeValue");
+    this.installInspectorControllerDelegate_("startTimelineProfiler");
+    this.installInspectorControllerDelegate_("stopTimelineProfiler");
+    this.installInspectorControllerDelegate_("storeLastActivePanel");
+};
+devtools.InspectorBackendImpl.prototype.__proto__ = WebInspector.InspectorBackendStub.prototype;
+
+
+/**
+ * {@inheritDoc}.
+ */
+devtools.InspectorBackendImpl.prototype.toggleNodeSearch = function()
+{
+    WebInspector.InspectorBackendStub.prototype.toggleNodeSearch.call(this);
+    this.callInspectorController_.call(this, "toggleNodeSearch");
+    if (!this.searchingForNode()) {
+        // This is called from ElementsPanel treeOutline's focusNodeChanged().
+        DevToolsHost.activateWindow();
+    }
+};
+
+
+/**
+ * @override
+ */
+devtools.InspectorBackendImpl.prototype.debuggerEnabled = function()
+{
+    return true;
+};
+
+
+/**
+ * @override
+ */
+devtools.InspectorBackendImpl.prototype.profilerEnabled = function()
+{
+    return true;
+};
+
+
+devtools.InspectorBackendImpl.prototype.addBreakpoint = function(sourceID, line, condition)
+{
+    devtools.tools.getDebuggerAgent().addBreakpoint(sourceID, line, condition);
+};
+
+
+devtools.InspectorBackendImpl.prototype.removeBreakpoint = function(sourceID, line)
+{
+    devtools.tools.getDebuggerAgent().removeBreakpoint(sourceID, line);
+};
+
+devtools.InspectorBackendImpl.prototype.updateBreakpoint = function(sourceID, line, condition)
+{
+    devtools.tools.getDebuggerAgent().updateBreakpoint(sourceID, line, condition);
+};
+
+devtools.InspectorBackendImpl.prototype.pauseInDebugger = function()
+{
+    devtools.tools.getDebuggerAgent().pauseExecution();
+};
+
+
+devtools.InspectorBackendImpl.prototype.resumeDebugger = function()
+{
+    devtools.tools.getDebuggerAgent().resumeExecution();
+};
+
+
+devtools.InspectorBackendImpl.prototype.stepIntoStatementInDebugger = function()
+{
+    devtools.tools.getDebuggerAgent().stepIntoStatement();
+};
+
+
+devtools.InspectorBackendImpl.prototype.stepOutOfFunctionInDebugger = function()
+{
+    devtools.tools.getDebuggerAgent().stepOutOfFunction();
+};
+
+
+devtools.InspectorBackendImpl.prototype.stepOverStatementInDebugger = function()
+{
+    devtools.tools.getDebuggerAgent().stepOverStatement();
+};
+
+/**
+ * @override
+ */
+devtools.InspectorBackendImpl.prototype.setPauseOnExceptionsState = function(state)
+{
+    this._setPauseOnExceptionsState = state;
+    // TODO(yurys): support all three states. See http://crbug.com/32877
+    var enabled = (state !== WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions);
+    return devtools.tools.getDebuggerAgent().setPauseOnExceptions(enabled);
+};
+
+/**
+ * @override
+ */
+devtools.InspectorBackendImpl.prototype.pauseOnExceptionsState = function()
+{
+    return (this._setPauseOnExceptionsState || WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions);
+};
+
+/**
+ * @override
+ */
+devtools.InspectorBackendImpl.prototype.pauseOnExceptions = function()
+{
+    return devtools.tools.getDebuggerAgent().pauseOnExceptions();
+};
+
+
+/**
+ * @override
+ */
+devtools.InspectorBackendImpl.prototype.setPauseOnExceptions = function(value)
+{
+    return devtools.tools.getDebuggerAgent().setPauseOnExceptions(value);
+};
+
+
+/**
+ * @override
+ */
+devtools.InspectorBackendImpl.prototype.startProfiling = function()
+{
+    devtools.tools.getProfilerAgent().startProfiling(devtools.ProfilerAgent.ProfilerModules.PROFILER_MODULE_CPU);
+};
+
+
+/**
+ * @override
+ */
+devtools.InspectorBackendImpl.prototype.stopProfiling = function()
+{
+    devtools.tools.getProfilerAgent().stopProfiling( devtools.ProfilerAgent.ProfilerModules.PROFILER_MODULE_CPU);
+};
+
+
+/**
+ * @override
+ */
+devtools.InspectorBackendImpl.prototype.getProfileHeaders = function(callId)
+{
+    WebInspector.didGetProfileHeaders(callId, []);
+};
+
+
+/**
+ * Emulate WebKit InspectorController behavior. It stores profiles on renderer side,
+ * and is able to retrieve them by uid using "getProfile".
+ */
+devtools.InspectorBackendImpl.prototype.addFullProfile = function(profile)
+{
+    WebInspector.__fullProfiles = WebInspector.__fullProfiles || {};
+    WebInspector.__fullProfiles[profile.uid] = profile;
+};
+
+
+/**
+ * @override
+ */
+devtools.InspectorBackendImpl.prototype.getProfile = function(callId, uid)
+{
+    if (WebInspector.__fullProfiles && (uid in WebInspector.__fullProfiles))
+        WebInspector.didGetProfile(callId, WebInspector.__fullProfiles[uid]);
+};
+
+
+/**
+ * @override
+ */
+devtools.InspectorBackendImpl.prototype.takeHeapSnapshot = function()
+{
+    devtools.tools.getProfilerAgent().startProfiling(devtools.ProfilerAgent.ProfilerModules.PROFILER_MODULE_HEAP_SNAPSHOT
+        | devtools.ProfilerAgent.ProfilerModules.PROFILER_MODULE_HEAP_STATS
+        | devtools.ProfilerAgent.ProfilerModules.PROFILER_MODULE_JS_CONSTRUCTORS);
+};
+
+
+/**
+ * @override
+ */
+devtools.InspectorBackendImpl.prototype.dispatchOnInjectedScript = function(callId, injectedScriptId, methodName, argsString, async)
+{
+    // Encode injectedScriptId into callId
+    if (typeof injectedScriptId !== "number")
+        injectedScriptId = 0;
+    RemoteToolsAgent.dispatchOnInjectedScript(callId, injectedScriptId, methodName, argsString, async);
+};
+
+
+/**
+ * Installs delegating handler into the inspector controller.
+ * @param {string} methodName Method to install delegating handler for.
+ */
+devtools.InspectorBackendImpl.prototype.installInspectorControllerDelegate_ = function(methodName)
+{
+    this[methodName] = this.callInspectorController_.bind(this, methodName);
+};
+
+
+/**
+ * Bound function with the installInjectedScriptDelegate_ actual
+ * implementation.
+ */
+devtools.InspectorBackendImpl.prototype.callInspectorController_ = function(methodName, var_arg)
+{
+    var args = Array.prototype.slice.call(arguments, 1);
+    RemoteToolsAgent.dispatchOnInspectorController(WebInspector.Callback.wrap(function(){}), methodName, JSON.stringify(args));
+};
+
+
+InspectorBackend = new devtools.InspectorBackendImpl();
diff --git a/WebKit/chromium/src/js/ProfilerAgent.js b/WebKit/chromium/src/js/ProfilerAgent.js
new file mode 100644
index 0000000..024030b
--- /dev/null
+++ b/WebKit/chromium/src/js/ProfilerAgent.js
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @fileoverview Provides communication interface to remote v8 profiler.
+ */
+
+/**
+ * FIXME: change field naming style to use trailing underscore.
+ * @constructor
+ */
+devtools.ProfilerAgent = function()
+{
+    RemoteProfilerAgent.didGetActiveProfilerModules = this.didGetActiveProfilerModules_.bind(this);
+    RemoteProfilerAgent.didGetLogLines = this.didGetLogLines_.bind(this);
+
+    /**
+     * Active profiler modules flags.
+     * @type {number}
+     */
+    this.activeProfilerModules_ = devtools.ProfilerAgent.ProfilerModules.PROFILER_MODULE_NONE;
+
+    /**
+     * Interval for polling profiler state.
+     * @type {number}
+     */
+    this.getActiveProfilerModulesInterval_ = null;
+
+    /**
+     * Profiler log position.
+     * @type {number}
+     */
+    this.logPosition_ = 0;
+
+    /**
+     * Whether log contents retrieval must be forced next time.
+     * @type {boolean}
+     */
+    this.forceGetLogLines_ = false;
+
+    /**
+     * Profiler processor instance.
+     * @type {devtools.profiler.Processor}
+     */
+    this.profilerProcessor_ = new devtools.profiler.Processor();
+};
+
+
+/**
+ * A copy of enum from include/v8.h
+ * @enum {number}
+ */
+devtools.ProfilerAgent.ProfilerModules = {
+    PROFILER_MODULE_NONE: 0,
+    PROFILER_MODULE_CPU: 1,
+    PROFILER_MODULE_HEAP_STATS: 1 << 1,
+    PROFILER_MODULE_JS_CONSTRUCTORS: 1 << 2,
+    PROFILER_MODULE_HEAP_SNAPSHOT: 1 << 16
+};
+
+
+/**
+ * Sets up callbacks that deal with profiles processing.
+ */
+devtools.ProfilerAgent.prototype.setupProfilerProcessorCallbacks = function()
+{
+    // A temporary icon indicating that the profile is being processed.
+    var processingIcon = new WebInspector.SidebarTreeElement(
+        "profile-sidebar-tree-item",
+        WebInspector.UIString("Processing..."),
+        '', null, false);
+    var profilesSidebar = WebInspector.panels.profiles.getProfileType(WebInspector.CPUProfileType.TypeId).treeElement;
+
+    this.profilerProcessor_.setCallbacks(
+        function onProfileProcessingStarted() {
+            // Set visually empty string. Subtitle hiding is done via styles
+            // manipulation which doesn't play well with dynamic append / removal.
+            processingIcon.subtitle = " ";
+            profilesSidebar.appendChild(processingIcon);
+        },
+        function onProfileProcessingStatus(ticksCount) {
+            processingIcon.subtitle = WebInspector.UIString("%d ticks processed", ticksCount);
+        },
+        function onProfileProcessingFinished(profile) {
+            profilesSidebar.removeChild(processingIcon);
+            profile.typeId = WebInspector.CPUProfileType.TypeId;
+            InspectorBackend.addFullProfile(profile);
+            WebInspector.addProfileHeader(profile);
+            // If no profile is currently shown, show the new one.
+            var profilesPanel = WebInspector.panels.profiles;
+            if (!profilesPanel.visibleView) {
+                profilesPanel.showProfile(profile);
+            }
+        }
+    );
+};
+
+
+/**
+ * Initializes profiling state.
+ */
+devtools.ProfilerAgent.prototype.initializeProfiling = function()
+{
+    this.setupProfilerProcessorCallbacks();
+    this.forceGetLogLines_ = true;
+    this.getActiveProfilerModulesInterval_ = setInterval(function() { RemoteProfilerAgent.getActiveProfilerModules(); }, 1000);
+};
+
+
+/**
+ * Starts profiling.
+ * @param {number} modules List of modules to enable.
+ */
+devtools.ProfilerAgent.prototype.startProfiling = function(modules)
+{
+    var cmd = new devtools.DebugCommand("profile", {
+        "modules": modules,
+        "command": "resume"});
+    devtools.DebuggerAgent.sendCommand_(cmd);
+    RemoteToolsAgent.executeVoidJavaScript();
+    if (modules & devtools.ProfilerAgent.ProfilerModules.PROFILER_MODULE_HEAP_SNAPSHOT) {
+        var pos = this.logPosition_;
+        // Active modules will not change, instead, a snapshot will be logged.
+        setTimeout(function() { RemoteProfilerAgent.getLogLines(pos); }, 500);
+    }
+};
+
+
+/**
+ * Stops profiling.
+ */
+devtools.ProfilerAgent.prototype.stopProfiling = function(modules)
+{
+    var cmd = new devtools.DebugCommand("profile", {
+        "modules": modules,
+        "command": "pause"});
+    devtools.DebuggerAgent.sendCommand_(cmd);
+    RemoteToolsAgent.executeVoidJavaScript();
+};
+
+
+/**
+ * Handles current profiler status.
+ * @param {number} modules List of active (started) modules.
+ */
+devtools.ProfilerAgent.prototype.didGetActiveProfilerModules_ = function(modules)
+{
+    var profModules = devtools.ProfilerAgent.ProfilerModules;
+    var profModuleNone = profModules.PROFILER_MODULE_NONE;
+    if (this.forceGetLogLines_ || (modules !== profModuleNone && this.activeProfilerModules_ === profModuleNone)) {
+        this.forceGetLogLines_ = false;
+        // Start to query log data.
+        RemoteProfilerAgent.getLogLines(this.logPosition_);
+    }
+    this.activeProfilerModules_ = modules;
+    // Update buttons.
+    WebInspector.setRecordingProfile(modules & profModules.PROFILER_MODULE_CPU);
+};
+
+
+/**
+ * Handles a portion of a profiler log retrieved by getLogLines call.
+ * @param {number} pos Current position in log.
+ * @param {string} log A portion of profiler log.
+ */
+devtools.ProfilerAgent.prototype.didGetLogLines_ = function(pos, log)
+{
+    this.logPosition_ = pos;
+    if (log.length > 0)
+        this.profilerProcessor_.processLogChunk(log);
+    else if (this.activeProfilerModules_ === devtools.ProfilerAgent.ProfilerModules.PROFILER_MODULE_NONE) {
+        // No new data and profiling is stopped---suspend log reading.
+        return;
+    }
+    setTimeout(function() { RemoteProfilerAgent.getLogLines(pos); }, 500);
+};
diff --git a/WebKit/chromium/src/js/ProfilerProcessor.js b/WebKit/chromium/src/js/ProfilerProcessor.js
new file mode 100644
index 0000000..f678d2c
--- /dev/null
+++ b/WebKit/chromium/src/js/ProfilerProcessor.js
@@ -0,0 +1,543 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @fileoverview Profiler processor is used to process log file produced
+ * by V8 and produce an internal profile representation which is used
+ * for building profile views in "Profiles" tab.
+ */
+
+
+/**
+ * Creates a Profile View builder object compatible with WebKit Profiler UI.
+ *
+ * @param {number} samplingRate Number of ms between profiler ticks.
+ * @constructor
+ */
+devtools.profiler.WebKitViewBuilder = function(samplingRate)
+{
+    devtools.profiler.ViewBuilder.call(this, samplingRate);
+};
+devtools.profiler.WebKitViewBuilder.prototype.__proto__ = devtools.profiler.ViewBuilder.prototype;
+
+
+/**
+ * @override
+ */
+devtools.profiler.WebKitViewBuilder.prototype.createViewNode = function(funcName, totalTime, selfTime, head)
+{
+    return new devtools.profiler.WebKitViewNode(funcName, totalTime, selfTime, head);
+};
+
+
+/**
+ * Constructs a Profile View node object for displaying in WebKit Profiler UI.
+ *
+ * @param {string} internalFuncName A fully qualified function name.
+ * @param {number} totalTime Amount of time that application spent in the
+ *     corresponding function and its descendants (not that depending on
+ *     profile they can be either callees or callers.)
+ * @param {number} selfTime Amount of time that application spent in the
+ *     corresponding function only.
+ * @param {devtools.profiler.ProfileView.Node} head Profile view head.
+ * @constructor
+ */
+devtools.profiler.WebKitViewNode = function(internalFuncName, totalTime, selfTime, head)
+{
+    devtools.profiler.ProfileView.Node.call(this, internalFuncName, totalTime, selfTime, head);
+    this.initFuncInfo_();
+    this.callUID = internalFuncName;
+};
+devtools.profiler.WebKitViewNode.prototype.__proto__ = devtools.profiler.ProfileView.Node.prototype;
+
+
+/**
+ * RegEx for stripping V8's prefixes of compiled functions.
+ */
+devtools.profiler.WebKitViewNode.FUNC_NAME_STRIP_RE = /^(?:LazyCompile|Function|Callback): (.*)$/;
+
+
+/**
+ * RegEx for extracting script source URL and line number.
+ */
+devtools.profiler.WebKitViewNode.FUNC_NAME_PARSE_RE = /^((?:get | set )?[^ ]+) (.*):(\d+)( \{\d+\})?$/;
+
+
+/**
+ * Inits "functionName", "url", and "lineNumber" fields using "internalFuncName"
+ * field.
+ * @private
+ */
+devtools.profiler.WebKitViewNode.prototype.initFuncInfo_ = function()
+{
+    var nodeAlias = devtools.profiler.WebKitViewNode;
+    this.functionName = this.internalFuncName;
+
+    var strippedName = nodeAlias.FUNC_NAME_STRIP_RE.exec(this.functionName);
+    if (strippedName)
+        this.functionName = strippedName[1];
+
+    var parsedName = nodeAlias.FUNC_NAME_PARSE_RE.exec(this.functionName);
+    if (parsedName) {
+        this.functionName = parsedName[1];
+        if (parsedName[4])
+            this.functionName += parsedName[4];
+        this.url = parsedName[2];
+        this.lineNumber = parsedName[3];
+    } else {
+        this.url = '';
+        this.lineNumber = 0;
+    }
+};
+
+
+/**
+ * Ancestor of a profile object that leaves out only JS-related functions.
+ * @constructor
+ */
+devtools.profiler.JsProfile = function()
+{
+    devtools.profiler.Profile.call(this);
+};
+devtools.profiler.JsProfile.prototype.__proto__ = devtools.profiler.Profile.prototype;
+
+
+/**
+ * RegExp that leaves only non-native JS functions.
+ * @type {RegExp}
+ */
+devtools.profiler.JsProfile.JS_NON_NATIVE_RE = new RegExp(
+      "^" +
+        "(?:Callback:)|" +
+        "(?:Script: (?!native))|" +
+        "(?:(?:LazyCompile|Function): [^ ]*(?: (?!native )[^ ]+:\\d+)?$)");
+
+
+/**
+ * @override
+ */
+devtools.profiler.JsProfile.prototype.skipThisFunction = function(name)
+{
+    return !devtools.profiler.JsProfile.JS_NON_NATIVE_RE.test(name);
+};
+
+
+/**
+ * Profiler processor. Consumes profiler log and builds profile views.
+ * FIXME: change field naming style to use trailing underscore.
+ *
+ * @param {function(devtools.profiler.ProfileView)} newProfileCallback Callback
+ *     that receives a new processed profile.
+ * @constructor
+ */
+devtools.profiler.Processor = function()
+{
+    var dispatches = {
+        "code-creation": {
+            parsers: [null, this.createAddressParser("code"), parseInt, null],
+            processor: this.processCodeCreation_, backrefs: true,
+            needsProfile: true },
+        "code-move": { parsers: [this.createAddressParser("code"),
+            this.createAddressParser("code-move-to")],
+            processor: this.processCodeMove_, backrefs: true,
+            needsProfile: true },
+        "code-delete": { parsers: [this.createAddressParser("code")],
+            processor: this.processCodeDelete_, backrefs: true,
+            needsProfile: true },
+        "function-creation": { parsers: [this.createAddressParser("code"),
+            this.createAddressParser("function-obj")],
+            processor: this.processFunctionCreation_, backrefs: true },
+        "function-move": { parsers: [this.createAddressParser("code"),
+            this.createAddressParser("code-move-to")],
+            processor: this.processFunctionMove_, backrefs: true },
+        "function-delete": { parsers: [this.createAddressParser("code")],
+            processor: this.processFunctionDelete_, backrefs: true },
+        "tick": { parsers: [this.createAddressParser("code"),
+            this.createAddressParser("stack"), parseInt, "var-args"],
+            processor: this.processTick_, backrefs: true, needProfile: true },
+        "profiler": { parsers: [null, "var-args"],
+            processor: this.processProfiler_, needsProfile: false },
+        "heap-sample-begin": { parsers: [null, null, parseInt],
+            processor: this.processHeapSampleBegin_ },
+        "heap-sample-stats": { parsers: [null, null, parseInt, parseInt],
+            processor: this.processHeapSampleStats_ },
+        "heap-sample-item": { parsers: [null, parseInt, parseInt],
+            processor: this.processHeapSampleItem_ },
+        "heap-js-cons-item": { parsers: [null, parseInt, parseInt],
+            processor: this.processHeapJsConsItem_ },
+        "heap-js-ret-item": { parsers: [null, "var-args"],
+            processor: this.processHeapJsRetItem_ },
+        "heap-sample-end": { parsers: [null, null],
+            processor: this.processHeapSampleEnd_ },
+        // Not used in DevTools Profiler.
+        "shared-library": null,
+        // Obsolete row types.
+        "code-allocate": null,
+        "begin-code-region": null,
+        "end-code-region": null};
+
+    if (devtools.profiler.Profile.VERSION === 2) {
+        dispatches["tick"] =  { parsers: [this.createAddressParser("code"),
+            this.createAddressParser("stack"),
+            this.createAddressParser("func"), parseInt, "var-args"],
+            processor: this.processTickV2_, backrefs: true };
+    }
+
+    devtools.profiler.LogReader.call(this, dispatches);
+
+    /**
+     * Callback that is called when a new profile is encountered in the log.
+     * @type {function()}
+     */
+    this.startedProfileProcessing_ = null;
+
+    /**
+     * Callback that is called periodically to display processing status.
+     * @type {function()}
+     */
+    this.profileProcessingStatus_ = null;
+
+    /**
+     * Callback that is called when a profile has been processed and is ready
+     * to be shown.
+     * @type {function(devtools.profiler.ProfileView)}
+     */
+    this.finishedProfileProcessing_ = null;
+
+    /**
+     * The current profile.
+     * @type {devtools.profiler.JsProfile}
+     */
+    this.currentProfile_ = null;
+
+    /**
+     * Builder of profile views. Created during "profiler,begin" event processing.
+     * @type {devtools.profiler.WebKitViewBuilder}
+     */
+    this.viewBuilder_ = null;
+
+    /**
+     * Next profile id.
+     * @type {number}
+     */
+    this.profileId_ = 1;
+
+    /**
+     * Counter for processed ticks.
+     * @type {number}
+     */
+    this.ticksCount_ = 0;
+
+    /**
+     * Interval id for updating processing status.
+     * @type {number}
+     */
+    this.processingInterval_ = null;
+
+    /**
+     * The current heap snapshot.
+     * @type {string}
+     */
+    this.currentHeapSnapshot_ = null;
+
+    /**
+     * Next heap snapshot id.
+     * @type {number}
+     */
+    this.heapSnapshotId_ = 1;
+};
+devtools.profiler.Processor.prototype.__proto__ = devtools.profiler.LogReader.prototype;
+
+
+/**
+ * @override
+ */
+devtools.profiler.Processor.prototype.printError = function(str)
+{
+    debugPrint(str);
+};
+
+
+/**
+ * @override
+ */
+devtools.profiler.Processor.prototype.skipDispatch = function(dispatch)
+{
+    return dispatch.needsProfile && this.currentProfile_ === null;
+};
+
+
+/**
+ * Sets profile processing callbacks.
+ *
+ * @param {function()} started Started processing callback.
+ * @param {function(devtools.profiler.ProfileView)} finished Finished
+ *     processing callback.
+ */
+devtools.profiler.Processor.prototype.setCallbacks = function(started, processing, finished)
+{
+    this.startedProfileProcessing_ = started;
+    this.profileProcessingStatus_ = processing;
+    this.finishedProfileProcessing_ = finished;
+};
+
+
+/**
+ * An address for the fake "(program)" entry. WebKit's visualisation
+ * has assumptions on how the top of the call tree should look like,
+ * and we need to add a fake entry as the topmost function. This
+ * address is chosen because it's the end address of the first memory
+ * page, which is never used for code or data, but only as a guard
+ * page for catching AV errors.
+ *
+ * @type {number}
+ */
+devtools.profiler.Processor.PROGRAM_ENTRY = 0xffff;
+/**
+ * @type {string}
+ */
+devtools.profiler.Processor.PROGRAM_ENTRY_STR = "0xffff";
+
+
+/**
+ * Sets new profile callback.
+ * @param {function(devtools.profiler.ProfileView)} callback Callback function.
+ */
+devtools.profiler.Processor.prototype.setNewProfileCallback = function(callback)
+{
+    this.newProfileCallback_ = callback;
+};
+
+
+devtools.profiler.Processor.prototype.processProfiler_ = function(state, params)
+{
+    switch (state) {
+        case "resume":
+            if (this.currentProfile_ === null) {
+                this.currentProfile_ = new devtools.profiler.JsProfile();
+                // see the comment for devtools.profiler.Processor.PROGRAM_ENTRY
+                this.currentProfile_.addCode("Function", "(program)", devtools.profiler.Processor.PROGRAM_ENTRY, 1);
+                if (this.startedProfileProcessing_)
+                    this.startedProfileProcessing_();
+                this.ticksCount_ = 0;
+                var self = this;
+                if (this.profileProcessingStatus_) {
+                    this.processingInterval_ = window.setInterval(
+                        function() { self.profileProcessingStatus_(self.ticksCount_); },
+                        1000);
+                }
+            }
+            break;
+        case "pause":
+            if (this.currentProfile_ !== null) {
+                window.clearInterval(this.processingInterval_);
+                this.processingInterval_ = null;
+                if (this.finishedProfileProcessing_)
+                    this.finishedProfileProcessing_(this.createProfileForView());
+                this.currentProfile_ = null;
+            }
+            break;
+        case "begin":
+            var samplingRate = NaN;
+            if (params.length > 0)
+                samplingRate = parseInt(params[0]);
+            if (isNaN(samplingRate))
+                samplingRate = 1;
+            this.viewBuilder_ = new devtools.profiler.WebKitViewBuilder(samplingRate);
+            break;
+        // These events are valid but aren't used.
+        case "compression":
+        case "end": break;
+        default:
+            throw new Error("unknown profiler state: " + state);
+    }
+};
+
+
+devtools.profiler.Processor.prototype.processCodeCreation_ = function(type, start, size, name)
+{
+    this.currentProfile_.addCode(this.expandAlias(type), name, start, size);
+};
+
+
+devtools.profiler.Processor.prototype.processCodeMove_ = function(from, to)
+{
+    this.currentProfile_.moveCode(from, to);
+};
+
+
+devtools.profiler.Processor.prototype.processCodeDelete_ = function(start)
+{
+    this.currentProfile_.deleteCode(start);
+};
+
+
+devtools.profiler.Processor.prototype.processFunctionCreation_ = function(functionAddr, codeAddr)
+{
+    this.currentProfile_.addCodeAlias(functionAddr, codeAddr);
+};
+
+
+devtools.profiler.Processor.prototype.processFunctionMove_ = function(from, to)
+{
+    this.currentProfile_.safeMoveDynamicCode(from, to);
+};
+
+
+devtools.profiler.Processor.prototype.processFunctionDelete_ = function(start)
+{
+    this.currentProfile_.safeDeleteDynamicCode(start);
+};
+
+
+// TODO(mnaganov): Remove after next V8 roll.
+devtools.profiler.Processor.prototype.processTick_ = function(pc, sp, vmState, stack)
+{
+    // see the comment for devtools.profiler.Processor.PROGRAM_ENTRY
+    stack.push(devtools.profiler.Processor.PROGRAM_ENTRY_STR);
+    this.currentProfile_.recordTick(this.processStack(pc, stack));
+    this.ticksCount_++;
+};
+
+
+devtools.profiler.Processor.prototype.processTickV2_ = function(pc, sp, func, vmState, stack)
+{
+    // see the comment for devtools.profiler.Processor.PROGRAM_ENTRY
+    stack.push(devtools.profiler.Processor.PROGRAM_ENTRY_STR);
+
+
+    if (func) {
+        var funcEntry = this.currentProfile_.findEntry(func);
+        if (!funcEntry || !funcEntry.isJSFunction || !funcEntry.isJSFunction())
+            func = 0;
+        else {
+            var currEntry = this.currentProfile_.findEntry(pc);
+            if (!currEntry || !currEntry.isJSFunction || currEntry.isJSFunction()) {
+                func = 0;
+            }
+        }
+    }
+
+    this.currentProfile_.recordTick(this.processStack(pc, func, stack));
+    this.ticksCount_++;
+};
+
+
+devtools.profiler.Processor.prototype.processHeapSampleBegin_ = function(space, state, ticks)
+{
+    if (space !== "Heap") return;
+    this.currentHeapSnapshot_ = {
+        number: this.heapSnapshotId_++,
+        entries: {},
+        clusters: {},
+        lowlevels: {},
+        ticks: ticks
+    };
+};
+
+
+devtools.profiler.Processor.prototype.processHeapSampleStats_ = function(space, state, capacity, used)
+{
+    if (space !== "Heap") return;
+};
+
+
+devtools.profiler.Processor.prototype.processHeapSampleItem_ = function(item, number, size)
+{
+    if (!this.currentHeapSnapshot_) return;
+    this.currentHeapSnapshot_.lowlevels[item] = {
+        type: item, count: number, size: size
+    };
+};
+
+
+devtools.profiler.Processor.prototype.processHeapJsConsItem_ = function(item, number, size)
+{
+    if (!this.currentHeapSnapshot_) return;
+    this.currentHeapSnapshot_.entries[item] = {
+        cons: item, count: number, size: size, retainers: {}
+    };
+};
+
+
+devtools.profiler.Processor.prototype.processHeapJsRetItem_ = function(item, retainersArray)
+{
+    if (!this.currentHeapSnapshot_) return;
+    var rawRetainers = {};
+    for (var i = 0, n = retainersArray.length; i < n; ++i) {
+        var entry = retainersArray[i].split(";");
+        rawRetainers[entry[0]] = parseInt(entry[1], 10);
+    }
+
+    function mergeRetainers(entry) {
+        for (var rawRetainer in rawRetainers) {
+            var consName = rawRetainer.indexOf(":") !== -1 ? rawRetainer.split(":")[0] : rawRetainer;
+            if (!(consName in entry.retainers))
+                entry.retainers[consName] = { cons: consName, count: 0, clusters: {} };
+            var retainer = entry.retainers[consName];
+            retainer.count += rawRetainers[rawRetainer];
+            if (consName !== rawRetainer)
+                retainer.clusters[rawRetainer] = true;
+        }
+    }
+
+    if (item.indexOf(":") !== -1) {
+      // Array, Function, or Object instances cluster case.
+      if (!(item in this.currentHeapSnapshot_.clusters)) {
+          this.currentHeapSnapshot_.clusters[item] = {
+              cons: item, retainers: {}
+          };
+      }
+      mergeRetainers(this.currentHeapSnapshot_.clusters[item]);
+      item = item.split(":")[0];
+    }
+    mergeRetainers(this.currentHeapSnapshot_.entries[item]);
+};
+
+
+devtools.profiler.Processor.prototype.processHeapSampleEnd_ = function(space, state)
+{
+    if (space !== "Heap") return;
+    var snapshot = this.currentHeapSnapshot_;
+    this.currentHeapSnapshot_ = null;
+    WebInspector.panels.profiles.addSnapshot(snapshot);
+};
+
+
+/**
+ * Creates a profile for further displaying in ProfileView.
+ */
+devtools.profiler.Processor.prototype.createProfileForView = function()
+{
+    var profile = this.viewBuilder_.buildView(this.currentProfile_.getTopDownProfile());
+    profile.uid = this.profileId_++;
+    profile.title = UserInitiatedProfileName + "." + profile.uid;
+    return profile;
+};
diff --git a/WebKit/chromium/src/js/Tests.js b/WebKit/chromium/src/js/Tests.js
new file mode 100644
index 0000000..2405aee
--- /dev/null
+++ b/WebKit/chromium/src/js/Tests.js
@@ -0,0 +1,1862 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/**
+ * @fileoverview This file contains small testing framework along with the
+ * test suite for the frontend. These tests are a part of the continues build
+ * and are executed by the devtools_sanity_unittest.cc as a part of the
+ * Interactive UI Test suite.
+ * FIXME: change field naming style to use trailing underscore.
+ */
+
+if (window.domAutomationController) {
+
+var ___interactiveUiTestsMode = true;
+
+/**
+ * Test suite for interactive UI tests.
+ * @constructor
+ */
+TestSuite = function()
+{
+    this.controlTaken_ = false;
+    this.timerId_ = -1;
+};
+
+
+/**
+ * Reports test failure.
+ * @param {string} message Failure description.
+ */
+TestSuite.prototype.fail = function(message)
+{
+    if (this.controlTaken_)
+        this.reportFailure_(message);
+    else
+        throw message;
+};
+
+
+/**
+ * Equals assertion tests that expected === actual.
+ * @param {Object} expected Expected object.
+ * @param {Object} actual Actual object.
+ * @param {string} opt_message User message to print if the test fails.
+ */
+TestSuite.prototype.assertEquals = function(expected, actual, opt_message)
+{
+    if (expected !== actual) {
+        var message = "Expected: '" + expected + "', but was '" + actual + "'";
+        if (opt_message)
+            message = opt_message + "(" + message + ")";
+        this.fail(message);
+    }
+};
+
+
+/**
+ * True assertion tests that value == true.
+ * @param {Object} value Actual object.
+ * @param {string} opt_message User message to print if the test fails.
+ */
+TestSuite.prototype.assertTrue = function(value, opt_message)
+{
+    this.assertEquals(true, !!value, opt_message);
+};
+
+
+/**
+ * Contains assertion tests that string contains substring.
+ * @param {string} string Outer.
+ * @param {string} substring Inner.
+ */
+TestSuite.prototype.assertContains = function(string, substring)
+{
+    if (string.indexOf(substring) === -1)
+        this.fail("Expected to: '" + string + "' to contain '" + substring + "'");
+};
+
+
+/**
+ * Takes control over execution.
+ */
+TestSuite.prototype.takeControl = function()
+{
+    this.controlTaken_ = true;
+    // Set up guard timer.
+    var self = this;
+    this.timerId_ = setTimeout(function() {
+        self.reportFailure_("Timeout exceeded: 20 sec");
+    }, 20000);
+};
+
+
+/**
+ * Releases control over execution.
+ */
+TestSuite.prototype.releaseControl = function()
+{
+    if (this.timerId_ !== -1) {
+        clearTimeout(this.timerId_);
+        this.timerId_ = -1;
+    }
+    this.reportOk_();
+};
+
+
+/**
+ * Async tests use this one to report that they are completed.
+ */
+TestSuite.prototype.reportOk_ = function()
+{
+    window.domAutomationController.send("[OK]");
+};
+
+
+/**
+ * Async tests use this one to report failures.
+ */
+TestSuite.prototype.reportFailure_ = function(error)
+{
+    if (this.timerId_ !== -1) {
+        clearTimeout(this.timerId_);
+        this.timerId_ = -1;
+    }
+    window.domAutomationController.send("[FAILED] " + error);
+};
+
+
+/**
+ * Runs all global functions starting with "test" as unit tests.
+ */
+TestSuite.prototype.runTest = function(testName)
+{
+    try {
+        this[testName]();
+        if (!this.controlTaken_)
+            this.reportOk_();
+    } catch (e) {
+        this.reportFailure_(e);
+    }
+};
+
+
+/**
+ * @param {string} panelName Name of the panel to show.
+ */
+TestSuite.prototype.showPanel = function(panelName)
+{
+    // Open Scripts panel.
+    var toolbar = document.getElementById("toolbar");
+    var button = toolbar.getElementsByClassName(panelName)[0];
+    button.click();
+    this.assertEquals(WebInspector.panels[panelName], WebInspector.currentPanel);
+};
+
+
+/**
+ * Overrides the method with specified name until it's called first time.
+ * @param {Object} receiver An object whose method to override.
+ * @param {string} methodName Name of the method to override.
+ * @param {Function} override A function that should be called right after the
+ *     overriden method returns.
+ * @param {boolean} opt_sticky Whether restore original method after first run
+ *     or not.
+ */
+TestSuite.prototype.addSniffer = function(receiver, methodName, override, opt_sticky)
+{
+    var orig = receiver[methodName];
+    if (typeof orig !== "function")
+        this.fail("Cannot find method to override: " + methodName);
+    var test = this;
+    receiver[methodName] = function(var_args) {
+        try {
+            var result = orig.apply(this, arguments);
+        } finally {
+            if (!opt_sticky)
+                receiver[methodName] = orig;
+        }
+        // In case of exception the override won't be called.
+        try {
+            override.apply(this, arguments);
+        } catch (e) {
+            test.fail("Exception in overriden method '" + methodName + "': " + e);
+        }
+        return result;
+    };
+};
+
+
+// UI Tests
+
+
+/**
+ * Tests that the real injected host is present in the context.
+ */
+TestSuite.prototype.testHostIsPresent = function()
+{
+    this.assertTrue(typeof InspectorFrontendHost === "object" && !InspectorFrontendHost.isStub);
+};
+
+
+/**
+ * Tests elements tree has an "HTML" root.
+ */
+TestSuite.prototype.testElementsTreeRoot = function()
+{
+    var doc = WebInspector.domAgent.document;
+    this.assertEquals("HTML", doc.documentElement.nodeName);
+    this.assertTrue(doc.documentElement.hasChildNodes());
+};
+
+
+/**
+ * Tests that main resource is present in the system and that it is
+ * the only resource.
+ */
+TestSuite.prototype.testMainResource = function()
+{
+    var tokens = [];
+    var resources = WebInspector.resources;
+    for (var id in resources)
+        tokens.push(resources[id].lastPathComponent);
+    this.assertEquals("simple_page.html", tokens.join(","));
+};
+
+
+/**
+ * Tests that resources tab is enabled when corresponding item is selected.
+ */
+TestSuite.prototype.testEnableResourcesTab = function()
+{
+    this.showPanel("resources");
+
+    var test = this;
+    this.addSniffer(WebInspector, "updateResource",
+        function(identifier, payload) {
+            test.assertEquals("simple_page.html", payload.lastPathComponent);
+            WebInspector.panels.resources.refresh();
+            WebInspector.panels.resources.revealAndSelectItem(WebInspector.resources[identifier]);
+
+            test.releaseControl();
+        });
+
+    // Following call should lead to reload that we capture in the
+    // addResource override.
+    WebInspector.panels.resources._enableResourceTracking();
+
+    // We now have some time to report results to controller.
+    this.takeControl();
+};
+
+
+/**
+ * Tests that correct content length is reported for resources.
+ */
+TestSuite.prototype.testResourceContentLength = function()
+{
+    this.showPanel("resources");
+    var test = this;
+
+    var png = false;
+    var html = false;
+    this.addSniffer(WebInspector, "updateResource",
+        function(identifier, payload) {
+            if (!payload.didLengthChange)
+                return;
+            var resource = WebInspector.resources[identifier];
+            if (!resource || !resource.url)
+                return;
+            if (resource.url.search("image.html$") !== -1) {
+              var expectedLength = 87;
+              test.assertTrue(
+                  resource.contentLength <= expectedLength,
+                  "image.html content length is greater thatn expected.");
+              if (expectedLength === resource.contentLength)
+                  html = true;
+            } else if (resource.url.search("image.png") !== -1) {
+              var expectedLength = 257796;
+              test.assertTrue(
+                  resource.contentLength <= expectedLength,
+                  "image.png content length is greater than expected.");
+              if (expectedLength === resource.contentLength)
+                  png = true;
+            }
+            if (html && png) {
+              // Wait 1 second before releasing control to check that the content
+              // lengths are not updated anymore.
+              setTimeout(function() {
+                  test.releaseControl();
+              }, 1000);
+            }
+        }, true);
+
+    // Make sure resource tracking is on.
+    WebInspector.panels.resources._enableResourceTracking();
+    // Reload inspected page to update all resources.
+    test.evaluateInConsole_(
+        "window.location.reload(true);",
+         function(resultText) {
+             test.assertEquals("undefined", resultText, "Unexpected result of reload().");
+         });
+
+    // We now have some time to report results to controller.
+    this.takeControl();
+};
+
+
+/**
+ * Tests resource headers.
+ */
+TestSuite.prototype.testResourceHeaders = function()
+{
+    this.showPanel("resources");
+
+    var test = this;
+
+    var responseOk = false;
+    var timingOk = false;
+
+    this.addSniffer(WebInspector, "updateResource",
+        function(identifier, payload) {
+            var resource = this.resources[identifier];
+            if (!resource || resource.mainResource) {
+                // We are only interested in secondary resources in this test.
+                return;
+            }
+
+            var requestHeaders = JSON.stringify(resource.requestHeaders);
+            test.assertContains(requestHeaders, "Accept");
+
+            if (payload.didResponseChange) {
+                var responseHeaders = JSON.stringify(resource.responseHeaders);
+                test.assertContains(responseHeaders, "Content-type");
+                test.assertContains(responseHeaders, "Content-Length");
+                test.assertTrue(typeof resource.responseReceivedTime !== "undefined");
+                responseOk = true;
+            }
+
+            if (payload.didTimingChange) {
+                test.assertTrue(typeof resource.startTime !== "undefined");
+                timingOk = true;
+            }
+
+            if (payload.didCompletionChange) {
+                test.assertTrue(responseOk);
+                test.assertTrue(timingOk);
+                test.assertTrue(typeof resource.endTime !== "undefined");
+                test.releaseControl();
+            }
+        }, true);
+
+    WebInspector.panels.resources._enableResourceTracking();
+    this.takeControl();
+};
+
+
+/**
+ * Tests the mime type of a cached (HTTP 304) resource.
+ */
+TestSuite.prototype.testCachedResourceMimeType = function()
+{
+    this.showPanel("resources");
+
+    var test = this;
+    var hasReloaded = false;
+
+    this.addSniffer(WebInspector, "updateResource",
+        function(identifier, payload) {
+            var resource = this.resources[identifier];
+            if (!resource || resource.mainResource) {
+                // We are only interested in secondary resources in this test.
+                return;
+            }
+
+            if (payload.didResponseChange) {
+                // Test server uses a default mime type for JavaScript files.
+                test.assertEquals("text/html", payload.mimeType);
+                if (!hasReloaded) {
+                    hasReloaded = true;
+                    // Reload inspected page to update all resources.
+                    test.evaluateInConsole_("window.location.reload(true);", function() {});
+                } else
+                    test.releaseControl();
+            }
+
+        }, true);
+
+    WebInspector.panels.resources._enableResourceTracking();
+    this.takeControl();
+};
+
+
+/**
+ * Tests that profiler works.
+ */
+TestSuite.prototype.testProfilerTab = function()
+{
+    this.showPanel("profiles");
+
+    var test = this;
+    this.addSniffer(WebInspector.panels.profiles, "addProfileHeader",
+        function(typeOrProfile, profile) {
+            if (!profile)
+                profile = typeOrProfile;
+            var panel = WebInspector.panels.profiles;
+            panel.showProfile(profile);
+            var node = panel.visibleView.profileDataGridTree.children[0];
+            // Iterate over displayed functions and search for a function
+            // that is called "fib" or "eternal_fib". If found, it will mean
+            // that we actually have profiled page's code.
+            while (node) {
+                if (node.functionName.indexOf("fib") !== -1)
+                    test.releaseControl();
+                node = node.traverseNextNode(true, null, true);
+            }
+
+            test.fail();
+        });
+    var ticksCount = 0;
+    var tickRecord = "\nt,";
+    this.addSniffer(RemoteProfilerAgent, "didGetLogLines",
+        function(posIgnored, log) {
+            var pos = 0;
+            while ((pos = log.indexOf(tickRecord, pos)) !== -1) {
+                pos += tickRecord.length;
+                ticksCount++;
+            }
+            if (ticksCount > 100)
+                InspectorBackend.stopProfiling();
+        }, true);
+
+    InspectorBackend.startProfiling();
+    this.takeControl();
+};
+
+
+/**
+ * Tests that scripts tab can be open and populated with inspected scripts.
+ */
+TestSuite.prototype.testShowScriptsTab = function()
+{
+    this.showPanel("scripts");
+    var test = this;
+    // There should be at least main page script.
+    this._waitUntilScriptsAreParsed(["debugger_test_page.html$"],
+        function() {
+            test.releaseControl();
+        });
+    // Wait until all scripts are added to the debugger.
+    this.takeControl();
+};
+
+
+/**
+ * Tests that scripts tab is populated with inspected scripts even if it
+ * hadn't been shown by the moment inspected paged refreshed.
+ * @see http://crbug.com/26312
+ */
+TestSuite.prototype.testScriptsTabIsPopulatedOnInspectedPageRefresh = function()
+{
+    var test = this;
+    this.assertEquals(WebInspector.panels.elements, WebInspector.currentPanel, "Elements panel should be current one.");
+
+    this.addSniffer(devtools.DebuggerAgent.prototype, "reset", waitUntilScriptIsParsed);
+
+    // Reload inspected page. It will reset the debugger agent.
+    test.evaluateInConsole_(
+        "window.location.reload(true);",
+        function(resultText) {
+            test.assertEquals("undefined", resultText, "Unexpected result of reload().");
+        });
+
+    function waitUntilScriptIsParsed() {
+        var parsed = devtools.tools.getDebuggerAgent().parsedScripts_;
+        for (var id in parsed) {
+            var url = parsed[id].getUrl();
+            if (url && url.search("debugger_test_page.html$") !== -1) {
+                checkScriptsPanel();
+                return;
+            }
+        }
+        test.addSniffer(devtools.DebuggerAgent.prototype, "addScriptInfo_", waitUntilScriptIsParsed);
+    }
+
+    function checkScriptsPanel() {
+        test.showPanel("scripts");
+        test.assertTrue(test._scriptsAreParsed(["debugger_test_page.html$"]), "Inspected script not found in the scripts list");
+        test.releaseControl();
+    }
+
+    // Wait until all scripts are added to the debugger.
+    this.takeControl();
+};
+
+
+/**
+ * Tests that scripts list contains content scripts.
+ */
+TestSuite.prototype.testContentScriptIsPresent = function()
+{
+    this.showPanel("scripts");
+    var test = this;
+
+    test._waitUntilScriptsAreParsed(
+        ["page_with_content_script.html$", "simple_content_script.js$"],
+        function() {
+          test.releaseControl();
+        });
+
+    // Wait until all scripts are added to the debugger.
+    this.takeControl();
+};
+
+
+/**
+ * Tests that scripts are not duplicaed on Scripts tab switch.
+ */
+TestSuite.prototype.testNoScriptDuplicatesOnPanelSwitch = function()
+{
+    var test = this;
+
+    // There should be two scripts: one for the main page and another
+    // one which is source of console API(see
+    // InjectedScript._ensureCommandLineAPIInstalled).
+    var expectedScriptsCount = 2;
+    var parsedScripts = [];
+
+    this.showPanel("scripts");
+
+
+    function switchToElementsTab() {
+        test.showPanel("elements");
+        setTimeout(switchToScriptsTab, 0);
+    }
+
+    function switchToScriptsTab() {
+        test.showPanel("scripts");
+        setTimeout(checkScriptsPanel, 0);
+    }
+
+    function checkScriptsPanel() {
+        test.assertTrue(!!WebInspector.panels.scripts.visibleView, "No visible script view.");
+        test.assertTrue(test._scriptsAreParsed(["debugger_test_page.html$"]), "Some scripts are missing.");
+        checkNoDuplicates();
+        test.releaseControl();
+    }
+
+    function checkNoDuplicates() {
+        var scriptSelect = document.getElementById("scripts-files");
+        var options = scriptSelect.options;
+        for (var i = 0; i < options.length; i++) {
+            var scriptName = options[i].text;
+            for (var j = i + 1; j < options.length; j++)
+                test.assertTrue(scriptName !== options[j].text, "Found script duplicates: " + test.optionsToString_(options));
+        }
+    }
+
+    test._waitUntilScriptsAreParsed(
+        ["debugger_test_page.html$"],
+        function() {
+            checkNoDuplicates();
+            setTimeout(switchToElementsTab, 0);
+        });
+
+
+    // Wait until all scripts are added to the debugger.
+    this.takeControl();
+};
+
+
+/**
+ * Tests that a breakpoint can be set.
+ */
+TestSuite.prototype.testSetBreakpoint = function()
+{
+    var test = this;
+    this.showPanel("scripts");
+
+    var breakpointLine = 12;
+
+    this._waitUntilScriptsAreParsed(["debugger_test_page.html"],
+        function() {
+          test.showMainPageScriptSource_(
+              "debugger_test_page.html",
+              function(view, url) {
+                view._addBreakpoint(breakpointLine);
+                // Force v8 execution.
+                RemoteToolsAgent.executeVoidJavaScript();
+                test.waitForSetBreakpointResponse_(url, breakpointLine,
+                    function() {
+                        test.releaseControl();
+                    });
+              });
+        });
+
+    this.takeControl();
+};
+
+
+/**
+ * Tests that pause on exception works.
+ */
+TestSuite.prototype.testPauseOnException = function()
+{
+    this.showPanel("scripts");
+    var test = this;
+
+    // TODO(yurys): remove else branch once the states are supported.
+    if (WebInspector.ScriptsPanel.PauseOnExceptionsState) {
+        while (WebInspector.currentPanel.pauseOnExceptionButton.state !== WebInspector.ScriptsPanel.PauseOnExceptionsState.PauseOnUncaughtExceptions)
+            WebInspector.currentPanel.pauseOnExceptionButton.element.click();
+    } else {
+        // Make sure pause on exceptions is on.
+        if (!WebInspector.currentPanel.pauseOnExceptionButton.toggled)
+            WebInspector.currentPanel.pauseOnExceptionButton.element.click();
+    }
+
+    this._executeCodeWhenScriptsAreParsed("handleClick()", ["pause_on_exception.html$"]);
+
+    this._waitForScriptPause(
+        {
+            functionsOnStack: ["throwAnException", "handleClick", "(anonymous function)"],
+            lineNumber: 6,
+            lineText: "  return unknown_var;"
+        },
+        function() {
+            test.releaseControl();
+        });
+
+    this.takeControl();
+};
+
+
+// Tests that debugger works correctly if pause event occurs when DevTools
+// frontend is being loaded.
+TestSuite.prototype.testPauseWhenLoadingDevTools = function()
+{
+    this.showPanel("scripts");
+    var test = this;
+
+    var expectations = {
+            functionsOnStack: ["callDebugger"],
+            lineNumber: 8,
+            lineText: "  debugger;"
+        };
+
+
+    // Script execution can already be paused.
+    if (WebInspector.currentPanel.paused) {
+        var callFrame = WebInspector.currentPanel.sidebarPanes.callstack.selectedCallFrame;
+        this.assertEquals(expectations.functionsOnStack[0], callFrame.functionName);
+        var callbackInvoked = false;
+        this._checkSourceFrameWhenLoaded(expectations, function() {
+                callbackInvoked = true;
+                if (test.controlTaken_)
+                    test.releaseControl();
+            });
+        if (!callbackInvoked) {
+            test.takeControl();
+        }
+        return;
+    }
+
+    this._waitForScriptPause(
+        {
+            functionsOnStack: ["callDebugger"],
+            lineNumber: 8,
+            lineText: "  debugger;"
+        },
+        function() {
+            test.releaseControl();
+        });
+    this.takeControl();
+};
+
+
+// Tests that pressing "Pause" will pause script execution if the script
+// is already running.
+TestSuite.prototype.testPauseWhenScriptIsRunning = function()
+{
+    this.showPanel("scripts");
+    var test = this;
+
+    test.evaluateInConsole_(
+        'setTimeout("handleClick()" , 0)',
+        function(resultText) {
+          test.assertTrue(!isNaN(resultText), "Failed to get timer id: " + resultText);
+          testScriptPauseAfterDelay();
+        });
+
+    // Wait for some time to make sure that inspected page is running the
+    // infinite loop.
+    function testScriptPauseAfterDelay() {
+        setTimeout(testScriptPause, 300);
+    }
+
+    function testScriptPause() {
+        // The script should be in infinite loop. Click "Pause" button to
+        // pause it and wait for the result.
+        WebInspector.panels.scripts.pauseButton.click();
+
+        test._waitForScriptPause(
+            {
+                functionsOnStack: ["handleClick", "(anonymous function)"],
+                lineNumber: 5,
+                lineText: "  while(true) {"
+            },
+            function() {
+                test.releaseControl();
+            });
+    }
+
+    this.takeControl();
+};
+
+
+/**
+ * Serializes options collection to string.
+ * @param {HTMLOptionsCollection} options
+ * @return {string}
+ */
+TestSuite.prototype.optionsToString_ = function(options)
+{
+    var names = [];
+    for (var i = 0; i < options.length; i++)
+        names.push('"' + options[i].text + '"');
+    return names.join(",");
+};
+
+
+/**
+ * Ensures that main HTML resource is selected in Scripts panel and that its
+ * source frame is setup. Invokes the callback when the condition is satisfied.
+ * @param {HTMLOptionsCollection} options
+ * @param {function(WebInspector.SourceView,string)} callback
+ */
+TestSuite.prototype.showMainPageScriptSource_ = function(scriptName, callback)
+{
+    var test = this;
+
+    var scriptSelect = document.getElementById("scripts-files");
+    var options = scriptSelect.options;
+
+    test.assertTrue(options.length, "Scripts list is empty");
+
+    // Select page's script if it's not current option.
+    var scriptResource;
+    if (options[scriptSelect.selectedIndex].text === scriptName)
+        scriptResource = options[scriptSelect.selectedIndex].representedObject;
+    else {
+        var pageScriptIndex = -1;
+        for (var i = 0; i < options.length; i++) {
+            if (options[i].text === scriptName) {
+                pageScriptIndex = i;
+                break;
+            }
+        }
+        test.assertTrue(-1 !== pageScriptIndex, "Script with url " + scriptName + " not found among " + test.optionsToString_(options));
+        scriptResource = options[pageScriptIndex].representedObject;
+
+        // Current panel is "Scripts".
+        WebInspector.currentPanel._showScriptOrResource(scriptResource);
+        test.assertEquals(pageScriptIndex, scriptSelect.selectedIndex, "Unexpected selected option index.");
+    }
+
+    test.assertTrue(scriptResource instanceof WebInspector.Resource,
+                    "Unexpected resource class.");
+    test.assertTrue(!!scriptResource.url, "Resource URL is null.");
+    test.assertTrue(scriptResource.url.search(scriptName + "$") !== -1, "Main HTML resource should be selected.");
+
+    var scriptsPanel = WebInspector.panels.scripts;
+
+    var view = scriptsPanel.visibleView;
+    test.assertTrue(view instanceof WebInspector.SourceView);
+
+    if (!view.sourceFrame._loaded) {
+        test.addSniffer(view, "_sourceFrameSetupFinished", function(event) {
+            callback(view, scriptResource.url);
+        });
+    } else
+        callback(view, scriptResource.url);
+};
+
+
+/*
+ * Evaluates the code in the console as if user typed it manually and invokes
+ * the callback when the result message is received and added to the console.
+ * @param {string} code
+ * @param {function(string)} callback
+ */
+TestSuite.prototype.evaluateInConsole_ = function(code, callback)
+{
+    WebInspector.console.visible = true;
+    WebInspector.console.prompt.text = code;
+    WebInspector.console.promptElement.dispatchEvent( TestSuite.createKeyEvent("Enter"));
+
+    this.addSniffer(WebInspector.ConsoleView.prototype, "addMessage",
+        function(commandResult) {
+            callback(commandResult.toMessageElement().textContent);
+        });
+};
+
+
+/*
+ * Waits for "setbreakpoint" response, checks that corresponding breakpoint
+ * was successfully set and invokes the callback if it was.
+ * @param {string} scriptUrl
+ * @param {number} breakpointLine
+ * @param {function()} callback
+ */
+TestSuite.prototype.waitForSetBreakpointResponse_ = function(scriptUrl, breakpointLine, callback)
+{
+    var test = this;
+    test.addSniffer(
+        devtools.DebuggerAgent.prototype,
+        "handleSetBreakpointResponse_",
+        function(msg) {
+            var bps = this.urlToBreakpoints_[scriptUrl];
+            test.assertTrue(!!bps, "No breakpoints for line " + breakpointLine);
+            var line = devtools.DebuggerAgent.webkitToV8LineNumber_(breakpointLine);
+            test.assertTrue(!!bps[line].getV8Id(), "Breakpoint id was not assigned.");
+            callback();
+        });
+};
+
+
+/**
+ * Tests eval on call frame.
+ */
+TestSuite.prototype.testEvalOnCallFrame = function()
+{
+    this.showPanel("scripts");
+
+    var breakpointLine = 16;
+
+    var test = this;
+    this.addSniffer(devtools.DebuggerAgent.prototype, "handleScriptsResponse_",
+        function(msg) {
+          test.showMainPageScriptSource_(
+              "debugger_test_page.html",
+              function(view, url) {
+                  view._addBreakpoint(breakpointLine);
+                  // Force v8 execution.
+                  RemoteToolsAgent.executeVoidJavaScript();
+                  test.waitForSetBreakpointResponse_(url, breakpointLine, setBreakpointCallback);
+              });
+        });
+
+    function setBreakpointCallback() {
+      // Since breakpoints are ignored in evals' calculate() function is
+      // execute after zero-timeout so that the breakpoint is hit.
+      test.evaluateInConsole_(
+          'setTimeout("calculate(123)" , 0)',
+          function(resultText) {
+              test.assertTrue(!isNaN(resultText), "Failed to get timer id: " + resultText);
+              waitForBreakpointHit();
+          });
+    }
+
+    function waitForBreakpointHit() {
+      test.addSniffer(
+          devtools.DebuggerAgent.prototype,
+          "handleBacktraceResponse_",
+          function(msg) {
+            test.assertEquals(2, this.callFrames_.length, "Unexpected stack depth on the breakpoint. " + JSON.stringify(msg));
+            test.assertEquals("calculate", this.callFrames_[0].functionName, "Unexpected top frame function.");
+            // Evaluate "e+1" where "e" is an argument of "calculate" function.
+            test.evaluateInConsole_(
+                "e+1",
+                function(resultText) {
+                    test.assertEquals("124", resultText, 'Unexpected "e+1" value.');
+                    test.releaseControl();
+                });
+          });
+    }
+
+    this.takeControl();
+};
+
+
+/**
+ * Tests that console auto completion works when script execution is paused.
+ */
+TestSuite.prototype.testCompletionOnPause = function()
+{
+    this.showPanel("scripts");
+    var test = this;
+    this._executeCodeWhenScriptsAreParsed("handleClick()", ["completion_on_pause.html$"]);
+
+    this._waitForScriptPause(
+        {
+            functionsOnStack: ["innerFunction", "handleClick", "(anonymous function)"],
+            lineNumber: 9,
+            lineText: "    debugger;"
+        },
+        showConsole);
+
+    function showConsole() {
+        test.addSniffer(WebInspector.console, "afterShow", testLocalsCompletion);
+        WebInspector.showConsole();
+    }
+
+    function testLocalsCompletion() {
+        checkCompletions("th", ["parameter1", "closureLocal", "p", "createClosureLocal"], testThisCompletion);
+    }
+
+    function testThisCompletion() {
+        checkCompletions("this.", ["field1", "field2", "m"], testFieldCompletion);
+    }
+
+    function testFieldCompletion() {
+        checkCompletions("this.field1.", ["id", "name"], function() { test.releaseControl(); });
+    }
+
+    function checkCompletions(expression, expectedProperties, callback) {
+        test.addSniffer(WebInspector.console, "_reportCompletions",
+            function(bestMatchOnly, completionsReadyCallback, dotNotation, bracketNotation, prefix, result, isException) {
+                test.assertTrue(!isException, "Exception while collecting completions");
+                for (var i = 0; i < expectedProperties.length; i++) {
+                    var name = expectedProperties[i];
+                    test.assertTrue(result[name], "Name " + name + " not found among the completions: " + JSON.stringify(result));
+                }
+                setTimeout(callback, 0);
+            });
+      WebInspector.console.prompt.text = expression;
+      WebInspector.console.prompt.autoCompleteSoon();
+    }
+
+    this.takeControl();
+};
+
+
+/**
+ * Tests that inspected page doesn't hang on reload if it contains a syntax
+ * error and DevTools window is open.
+ */
+TestSuite.prototype.testAutoContinueOnSyntaxError = function()
+{
+    this.showPanel("scripts");
+    var test = this;
+
+    function checkScriptsList() {
+        var scriptSelect = document.getElementById("scripts-files");
+        var options = scriptSelect.options;
+        // There should be only console API source (see
+        // InjectedScript._ensureCommandLineAPIInstalled) since the page script
+        // contains a syntax error.
+        for (var i = 0 ; i < options.length; i++) {
+            if (options[i].text.search("script_syntax_error.html$") !== -1)
+                test.fail("Script with syntax error should not be in the list of parsed scripts.");
+        }
+    }
+
+    this.addSniffer(devtools.DebuggerAgent.prototype, "handleScriptsResponse_",
+        function(msg) {
+            checkScriptsList();
+
+            // Reload inspected page.
+            test.evaluateInConsole_(
+                "window.location.reload(true);",
+                function(resultText) {
+                    test.assertEquals("undefined", resultText, "Unexpected result of reload().");
+                    waitForExceptionEvent();
+                });
+        });
+
+    function waitForExceptionEvent() {
+      var exceptionCount = 0;
+      test.addSniffer(
+          devtools.DebuggerAgent.prototype,
+          "handleExceptionEvent_",
+          function(msg) {
+              exceptionCount++;
+              test.assertEquals(1, exceptionCount, "Too many exceptions.");
+              test.assertEquals(undefined, msg.getBody().script, "Unexpected exception: " + JSON.stringify(msg));
+              test.releaseControl();
+          });
+
+      // Check that the script is not paused on parse error.
+      test.addSniffer(
+          WebInspector,
+          "pausedScript",
+          function(callFrames) {
+              test.fail("Script execution should not pause on syntax error.");
+          });
+    }
+
+    this.takeControl();
+};
+
+
+/**
+ * Checks current execution line against expectations.
+ * @param {WebInspector.SourceFrame} sourceFrame
+ * @param {number} lineNumber Expected line number
+ * @param {string} lineContent Expected line text
+ */
+TestSuite.prototype._checkExecutionLine = function(sourceFrame, lineNumber, lineContent)
+{
+    this.assertEquals(lineNumber, sourceFrame.executionLine, "Unexpected execution line number.");
+    this.assertEquals(lineContent, sourceFrame._textModel.line(lineNumber - 1), "Unexpected execution line text.");
+}
+
+
+/**
+ * Checks that all expected scripts are present in the scripts list
+ * in the Scripts panel.
+ * @param {Array.<string>} expected Regular expressions describing
+ *     expected script names.
+ * @return {boolean} Whether all the scripts are in "scripts-files" select
+ *     box
+ */
+TestSuite.prototype._scriptsAreParsed = function(expected)
+{
+    var scriptSelect = document.getElementById("scripts-files");
+    var options = scriptSelect.options;
+
+    // Check that at least all the expected scripts are present.
+    var missing = expected.slice(0);
+    for (var i = 0 ; i < options.length; i++) {
+        for (var j = 0; j < missing.length; j++) {
+            if (options[i].text.search(missing[j]) !== -1) {
+                missing.splice(j, 1);
+                break;
+            }
+        }
+    }
+    return missing.length === 0;
+};
+
+
+/**
+ * Waits for script pause, checks expectations, and invokes the callback.
+ * @param {Object} expectations  Dictionary of expectations
+ * @param {function():void} callback
+ */
+TestSuite.prototype._waitForScriptPause = function(expectations, callback)
+{
+    var test = this;
+    // Wait until script is paused.
+    test.addSniffer(
+        WebInspector,
+        "pausedScript",
+        function(callFrames) {
+            var functionsOnStack = [];
+            for (var i = 0; i < callFrames.length; i++)
+                functionsOnStack.push(callFrames[i].functionName);
+
+            test.assertEquals(expectations.functionsOnStack.join(","), functionsOnStack.join(","), "Unexpected stack.");
+
+            // Check that execution line where the script is paused is
+            // expected one.
+            test._checkSourceFrameWhenLoaded(expectations, callback);
+        });
+};
+
+
+/**
+ * Waits for current source frame to load, checks expectations, and invokes
+ * the callback.
+ * @param {Object} expectations  Dictionary of expectations
+ * @param {function():void} callback
+ */
+TestSuite.prototype._checkSourceFrameWhenLoaded = function(expectations, callback)
+{
+    var test = this;
+
+    var frame = WebInspector.currentPanel.visibleView.sourceFrame;
+    if (frame._loaded)
+        checkExecLine();
+    else {
+        setTimeout(function() {
+            test._checkSourceFrameWhenLoaded(expectations, callback);
+        }, 100);
+    }
+    function checkExecLine() {
+        test._checkExecutionLine(frame, expectations.lineNumber, expectations.lineText);
+        callback();
+    }
+};
+
+
+/**
+ * Performs sequence of steps.
+ * @param {Array.<Object|Function>} Array [expectations1,action1,expectations2,
+ *     action2,...,actionN].
+ */
+TestSuite.prototype._performSteps = function(actions)
+{
+    var test = this;
+    var i = 0;
+    function doNextAction() {
+        if (i > 0)
+            actions[i++]();
+        if (i < actions.length - 1)
+            test._waitForScriptPause(actions[i++], doNextAction);
+    }
+    doNextAction();
+};
+
+
+/**
+ * Waits until all the scripts are parsed and asynchronously executes the code
+ * in the inspected page.
+ */
+TestSuite.prototype._executeCodeWhenScriptsAreParsed = function(code, expectedScripts)
+{
+    var test = this;
+
+    function executeFunctionInInspectedPage() {
+        // Since breakpoints are ignored in evals' calculate() function is
+        // execute after zero-timeout so that the breakpoint is hit.
+        test.evaluateInConsole_(
+            'setTimeout("' + code + '" , 0)',
+            function(resultText) {
+                test.assertTrue(!isNaN(resultText), "Failed to get timer id: " + resultText);
+            });
+    }
+
+    test._waitUntilScriptsAreParsed(expectedScripts, executeFunctionInInspectedPage);
+};
+
+
+/**
+ * Waits until all the scripts are parsed and invokes the callback.
+ */
+TestSuite.prototype._waitUntilScriptsAreParsed = function(expectedScripts, callback)
+{
+    var test = this;
+
+    function waitForAllScripts() {
+        if (test._scriptsAreParsed(expectedScripts))
+            callback();
+        else
+            test.addSniffer(WebInspector, "parsedScriptSource", waitForAllScripts);
+    }
+
+    waitForAllScripts();
+};
+
+
+/**
+ * Waits until all debugger scripts are parsed and executes "a()" in the
+ * inspected page.
+ */
+TestSuite.prototype._executeFunctionForStepTest = function()
+{
+    this._executeCodeWhenScriptsAreParsed("a()", ["debugger_step.html$", "debugger_step.js$"]);
+};
+
+
+/**
+ * Tests step over in the debugger.
+ */
+TestSuite.prototype.testStepOver = function()
+{
+    this.showPanel("scripts");
+    var test = this;
+
+    this._executeFunctionForStepTest();
+
+    this._performSteps([
+        {
+            functionsOnStack: ["d","a","(anonymous function)"],
+            lineNumber: 3,
+            lineText: "    debugger;"
+        },
+        function() {
+            document.getElementById("scripts-step-over").click();
+        },
+        {
+            functionsOnStack: ["d","a","(anonymous function)"],
+            lineNumber: 5,
+            lineText: "  var y = fact(10);"
+        },
+        function() {
+            document.getElementById("scripts-step-over").click();
+        },
+        {
+            functionsOnStack: ["d","a","(anonymous function)"],
+            lineNumber: 6,
+            lineText: "  return y;"
+        },
+        function() {
+            test.releaseControl();
+        }
+    ]);
+
+    test.takeControl();
+};
+
+
+/**
+ * Tests step out in the debugger.
+ */
+TestSuite.prototype.testStepOut = function()
+{
+    this.showPanel("scripts");
+    var test = this;
+
+    this._executeFunctionForStepTest();
+
+    this._performSteps([
+        {
+            functionsOnStack: ["d","a","(anonymous function)"],
+            lineNumber: 3,
+            lineText: "    debugger;"
+        },
+        function() {
+            document.getElementById("scripts-step-out").click();
+        },
+        {
+            functionsOnStack: ["a","(anonymous function)"],
+            lineNumber: 8,
+            lineText: "  printResult(result);"
+        },
+        function() {
+            test.releaseControl();
+        }
+    ]);
+
+    test.takeControl();
+};
+
+
+/**
+ * Tests step in in the debugger.
+ */
+TestSuite.prototype.testStepIn = function()
+{
+    this.showPanel("scripts");
+    var test = this;
+
+    this._executeFunctionForStepTest();
+
+    this._performSteps([
+        {
+            functionsOnStack: ["d","a","(anonymous function)"],
+            lineNumber: 3,
+            lineText: "    debugger;"
+        },
+        function() {
+            document.getElementById("scripts-step-over").click();
+        },
+        {
+            functionsOnStack: ["d","a","(anonymous function)"],
+            lineNumber: 5,
+            lineText: "  var y = fact(10);"
+        },
+        function() {
+            document.getElementById("scripts-step-into").click();
+        },
+        {
+            functionsOnStack: ["fact","d","a","(anonymous function)"],
+            lineNumber: 15,
+            lineText: "  return r;"
+        },
+        function() {
+            test.releaseControl();
+        }
+    ]);
+
+    test.takeControl();
+};
+
+
+/**
+ * Gets a XPathResult matching given xpath.
+ * @param {string} xpath
+ * @param {number} resultType
+ * @param {Node} opt_ancestor Context node. If not specified documentElement
+ *     will be used
+ * @return {XPathResult} Type of returned value is determined by "resultType" parameter
+ */
+
+TestSuite.prototype._evaluateXpath = function(xpath, resultType, opt_ancestor)
+{
+    if (!opt_ancestor)
+        opt_ancestor = document.documentElement;
+    try {
+        return document.evaluate(xpath, opt_ancestor, null, resultType, null);
+    } catch(e) {
+        this.fail('Error in expression: "' + xpath + '".' + e);
+    }
+};
+
+
+/**
+ * Gets first Node matching given xpath.
+ * @param {string} xpath
+ * @param {Node} opt_ancestor Context node. If not specified documentElement
+ *     will be used
+ * @return {?Node}
+ */
+TestSuite.prototype._findNode = function(xpath, opt_ancestor)
+{
+    var result = this._evaluateXpath(xpath, XPathResult.FIRST_ORDERED_NODE_TYPE, opt_ancestor).singleNodeValue;
+    this.assertTrue(!!result, "Cannot find node on path: " + xpath);
+    return result;
+};
+
+
+/**
+ * Gets a text matching given xpath.
+ * @param {string} xpath
+ * @param {Node} opt_ancestor Context node. If not specified documentElement
+ *     will be used
+ * @return {?string}
+ */
+TestSuite.prototype._findText = function(xpath, opt_ancestor)
+{
+    var result = this._evaluateXpath(xpath, XPathResult.STRING_TYPE, opt_ancestor).stringValue;
+    this.assertTrue(!!result, "Cannot find text on path: " + xpath);
+    return result;
+};
+
+
+/**
+ * Gets an iterator over nodes matching given xpath.
+ * @param {string} xpath
+ * @param {Node} opt_ancestor Context node. If not specified, documentElement
+ *     will be used
+ * @return {XPathResult} Iterator over the nodes
+ */
+TestSuite.prototype._nodeIterator = function(xpath, opt_ancestor)
+{
+    return this._evaluateXpath(xpath, XPathResult.ORDERED_NODE_ITERATOR_TYPE, opt_ancestor);
+};
+
+
+/**
+ * Checks the scopeSectionDiv against the expectations.
+ * @param {Node} scopeSectionDiv The section div
+ * @param {Object} expectations Expectations dictionary
+ */
+TestSuite.prototype._checkScopeSectionDiv = function(scopeSectionDiv, expectations)
+{
+    var scopeTitle = this._findText('./div[@class="header"]/div[@class="title"]/text()', scopeSectionDiv);
+    this.assertEquals(expectations.title, scopeTitle, "Unexpected scope section title.");
+    if (!expectations.properties)
+        return;
+    this.assertTrue(scopeSectionDiv.hasStyleClass("expanded"), 'Section "' + scopeTitle + '" is collapsed.');
+
+    var propertyIt = this._nodeIterator("./ol/li", scopeSectionDiv);
+    var propertyLi;
+    var foundProps = [];
+    while (propertyLi = propertyIt.iterateNext()) {
+        var name = this._findText('./span[@class="name"]/text()', propertyLi);
+        var value = this._findText('./span[@class="value"]/text()', propertyLi);
+        this.assertTrue(!!name, 'Invalid variable name: "' + name + '"');
+        this.assertTrue(name in expectations.properties, "Unexpected property: " + name);
+        this.assertEquals(expectations.properties[name], value, 'Unexpected "' + name + '" property value.');
+        delete expectations.properties[name];
+        foundProps.push(name + " = " + value);
+    }
+
+    // Check that all expected properties were found.
+    for (var p in expectations.properties)
+        this.fail('Property "' + p + '" was not found in scope "' + scopeTitle + '". Found properties: "' + foundProps.join(",") + '"');
+};
+
+
+/**
+ * Expands scope sections matching the filter and invokes the callback on
+ * success.
+ * @param {function(WebInspector.ObjectPropertiesSection, number):boolean}
+ *     filter
+ * @param {Function} callback
+ */
+TestSuite.prototype._expandScopeSections = function(filter, callback)
+{
+    var sections = WebInspector.currentPanel.sidebarPanes.scopechain.sections;
+
+    var toBeUpdatedCount = 0;
+    function updateListener() {
+        --toBeUpdatedCount;
+        if (toBeUpdatedCount === 0) {
+            // Report when all scopes are expanded and populated.
+            callback();
+        }
+    }
+
+    // Global scope is always the last one.
+    for (var i = 0; i < sections.length - 1; i++) {
+        var section = sections[i];
+        if (!filter(sections, i))
+            continue;
+        ++toBeUpdatedCount;
+        var populated = section.populated;
+
+        this._hookGetPropertiesCallback(updateListener,
+            function() {
+                section.expand();
+                if (populated) {
+                    // Make sure "updateProperties" callback will be called at least once
+                    // after it was overridden.
+                    section.update();
+                }
+            });
+    }
+};
+
+
+/**
+ * Tests that scopes can be expanded and contain expected data.
+ */
+TestSuite.prototype.testExpandScope = function()
+{
+    this.showPanel("scripts");
+    var test = this;
+
+    this._executeCodeWhenScriptsAreParsed("handleClick()", ["debugger_closure.html$"]);
+
+    this._waitForScriptPause(
+        {
+            functionsOnStack: ["innerFunction", "handleClick", "(anonymous function)"],
+            lineNumber: 8,
+            lineText: "    debugger;"
+        },
+        expandAllSectionsExceptGlobal);
+
+    // Expanding Global scope takes for too long so we skeep it.
+    function expandAllSectionsExceptGlobal() {
+        test._expandScopeSections(function(sections, i) {
+            return i < sections.length - 1;
+        },
+        examineScopes /* When all scopes are expanded and populated check them. */);
+    }
+
+    // Check scope sections contents.
+    function examineScopes() {
+        var scopeVariablesSection = test._findNode('//div[@id="scripts-sidebar"]/div[div[@class="title"]/text()="Scope Variables"]');
+        var expectedScopes = [
+            {
+                title: "Local",
+                properties: {
+                    x:"2009",
+                    innerFunctionLocalVar:"2011",
+                    "this": "global",
+                }
+            },
+            {
+                title: "Closure",
+                properties: {
+                    n:"TextParam",
+                    makeClosureLocalVar:"local.TextParam",
+                }
+            },
+            {
+                title: "Global",
+            },
+        ];
+        var it = test._nodeIterator('./div[@class="body"]/div', scopeVariablesSection);
+        var scopeIndex = 0;
+        var scopeDiv;
+        while (scopeDiv = it.iterateNext()) {
+            test.assertTrue(scopeIndex < expectedScopes.length, "Too many scopes.");
+            test._checkScopeSectionDiv(scopeDiv, expectedScopes[scopeIndex]);
+            ++scopeIndex;
+        }
+        test.assertEquals(expectedScopes.length, scopeIndex, "Unexpected number of scopes.");
+
+        test.releaseControl();
+    }
+
+    test.takeControl();
+};
+
+
+/**
+ * Returns child tree element for a property with given name.
+ * @param {TreeElement} parent Parent tree element.
+ * @param {string} childName
+ * @param {string} objectPath Path to the object. Will be printed in the case
+ *     of failure.
+ * @return {TreeElement}
+ */
+TestSuite.prototype._findChildProperty = function(parent, childName, objectPath)
+{
+    var children = parent.children;
+    for (var i = 0; i < children.length; i++) {
+        var treeElement = children[i];
+        var property = treeElement.property;
+        if (property.name === childName)
+            return treeElement;
+    }
+    this.fail('Cannot find property "' + childName + '" in ' + objectPath);
+};
+
+
+/**
+ * Executes the 'code' with InjectedScriptAccess.getProperties overriden
+ * so that all callbacks passed to InjectedScriptAccess.getProperties are
+ * extended with the "hook".
+ * @param {Function} hook The hook function.
+ * @param {Function} code A code snippet to be executed.
+ */
+TestSuite.prototype._hookGetPropertiesCallback = function(hook, code)
+{
+    var accessor = InjectedScriptAccess.prototype;
+    var orig = accessor.getProperties;
+    accessor.getProperties = function(objectProxy, ignoreHasOwnProperty, abbreviate, callback) {
+        orig.call(this, objectProxy, ignoreHasOwnProperty, abbreviate,
+            function() {
+              callback.apply(this, arguments);
+              hook();
+            });
+    };
+    try {
+        code();
+    } finally {
+        accessor.getProperties = orig;
+    }
+};
+
+
+/**
+ * Tests that all elements in prototype chain of an object have expected
+ * intrinic proprties(__proto__, constructor, prototype).
+ */
+TestSuite.prototype.testDebugIntrinsicProperties = function()
+{
+    this.showPanel("scripts");
+    var test = this;
+
+    this._executeCodeWhenScriptsAreParsed("handleClick()", ["debugger_intrinsic_properties.html$"]);
+
+    this._waitForScriptPause(
+        {
+            functionsOnStack: ["callDebugger", "handleClick", "(anonymous function)"],
+            lineNumber: 29,
+            lineText: "  debugger;"
+        },
+        expandLocalScope);
+
+    var localScopeSection = null;
+    function expandLocalScope() {
+      test._expandScopeSections(function(sections, i) {
+              if (i === 0) {
+                  test.assertTrue(sections[i].object.isLocal, "Scope #0 is not Local.");
+                  localScopeSection = sections[i];
+                  return true;
+              }
+              return false;
+          },
+          examineLocalScope);
+    }
+
+    function examineLocalScope() {
+      var scopeExpectations = [
+          "a", "Object", [
+              "constructor", "function Child()", [
+                  "constructor", "function Function()", null,
+                  "name", "Child", null,
+                  "prototype", "Object", [
+                      "childProtoField", 21, null
+                  ]
+              ],
+
+            "__proto__", "Object", [
+                  "__proto__", "Object", [
+                      "__proto__", "Object", [
+                          "__proto__", "null", null,
+                          "constructor", "function Object()", null,
+                      ],
+                    "constructor", "function Parent()", [
+                        "name", "Parent", null,
+                        "prototype", "Object", [
+                            "parentProtoField", 11, null,
+                        ]
+                    ],
+                    "parentProtoField", 11, null,
+                ],
+                "constructor", "function Child()", null,
+                "childProtoField", 21, null,
+            ],
+
+            "parentField", 10, null,
+            "childField", 20, null,
+          ]
+      ];
+
+      checkProperty(localScopeSection.propertiesTreeOutline, "<Local Scope>", scopeExpectations);
+    }
+
+    var propQueue = [];
+    var index = 0;
+    var expectedFinalIndex = 8;
+
+    function expandAndCheckNextProperty() {
+        if (index === propQueue.length) {
+            test.assertEquals(expectedFinalIndex, index, "Unexpected number of expanded objects.");
+            test.releaseControl();
+            return;
+        }
+
+        // Read next property data from the queue.
+        var treeElement = propQueue[index].treeElement;
+        var path = propQueue[index].path;
+        var expectations = propQueue[index].expectations;
+        index++;
+
+        // Expand the property.
+        test._hookGetPropertiesCallback(function() {
+                checkProperty(treeElement, path, expectations);
+            },
+            function() {
+                treeElement.expand();
+            });
+    }
+
+    function checkProperty(treeElement, path, expectations) {
+        for (var i = 0; i < expectations.length; i += 3) {
+            var name = expectations[i];
+            var description = expectations[i+1];
+            var value = expectations[i+2];
+
+            var propertyPath = path + "." + name;
+            var propertyTreeElement = test._findChildProperty(treeElement, name, path);
+            test.assertTrue(propertyTreeElement, 'Property "' + propertyPath + '" not found.');
+            test.assertEquals(description, propertyTreeElement.property.value.description, 'Unexpected "' + propertyPath + '" description.');
+            if (value) {
+                // Schedule property content check.
+                propQueue.push({
+                    treeElement: propertyTreeElement,
+                    path: propertyPath,
+                    expectations: value,
+                });
+            }
+        }
+        // Check next property in the queue.
+        expandAndCheckNextProperty();
+    }
+
+    test.takeControl();
+};
+
+
+/**
+ * Tests "Pause" button will pause debugger when a snippet is evaluated.
+ */
+TestSuite.prototype.testPauseInEval = function()
+{
+    this.showPanel("scripts");
+
+    var test = this;
+
+    var pauseButton = document.getElementById("scripts-pause");
+    pauseButton.click();
+
+    devtools.tools.evaluateJavaScript("fib(10)");
+
+    this.addSniffer(WebInspector, "pausedScript",
+        function() {
+            test.releaseControl();
+        });
+
+    test.takeControl();
+};
+
+
+/**
+ * Key event with given key identifier.
+ */
+TestSuite.createKeyEvent = function(keyIdentifier)
+{
+    var evt = document.createEvent("KeyboardEvent");
+    evt.initKeyboardEvent("keydown", true /* can bubble */, true /* can cancel */, null /* view */, keyIdentifier, "");
+    return evt;
+};
+
+
+/**
+ * Tests console eval.
+ */
+TestSuite.prototype.testConsoleEval = function()
+{
+    var test = this;
+    this.evaluateInConsole_("123",
+        function(resultText) {
+            test.assertEquals("123", resultText);
+            test.releaseControl();
+        });
+
+    this.takeControl();
+};
+
+
+/**
+ * Tests console log.
+ */
+TestSuite.prototype.testConsoleLog = function()
+{
+    WebInspector.console.visible = true;
+    var messages = WebInspector.console.messages;
+    var index = 0;
+
+    var test = this;
+    var assertNext = function(line, message, opt_class, opt_count, opt_substr) {
+        var elem = messages[index++].toMessageElement();
+        var clazz = elem.getAttribute("class");
+        var expectation = (opt_count || '') + 'console_test_page.html:' + line + message;
+        if (opt_substr)
+            test.assertContains(elem.textContent, expectation);
+        else
+            test.assertEquals(expectation, elem.textContent);
+        if (opt_class)
+            test.assertContains(clazz, "console-" + opt_class);
+    };
+
+    assertNext("5", "log", "log-level");
+    assertNext("7", "debug", "log-level");
+    assertNext("9", "info", "log-level");
+    assertNext("11", "warn", "warning-level");
+    assertNext("13", "error", "error-level");
+    assertNext("15", "Message format number 1, 2 and 3.5");
+    assertNext("17", "Message format for string");
+    assertNext("19", "Object Object");
+    assertNext("22", "repeated", "log-level", 5);
+    assertNext("26", "count: 1");
+    assertNext("26", "count: 2");
+    assertNext("29", "group", "group-title");
+    index++;
+    assertNext("33", "timer:", "log-level", "", true);
+    assertNext("35", "1 2 3", "log-level");
+    assertNext("37", "HTMLDocument", "log-level");
+    assertNext("39", "<html>", "log-level", "", true);
+};
+
+
+/**
+ * Tests eval of global objects.
+ */
+TestSuite.prototype.testEvalGlobal = function()
+{
+    WebInspector.console.visible = true;
+
+    var inputs = ["foo", "foobar"];
+    var expectations = ["foo", "fooValue", "foobar", "ReferenceError: foobar is not defined"];
+
+    // Do not change code below - simply add inputs and expectations above.
+    var initEval = function(input) {
+        WebInspector.console.prompt.text = input;
+        WebInspector.console.promptElement.dispatchEvent( TestSuite.createKeyEvent("Enter"));
+    };
+    var test = this;
+    var messagesCount = 0;
+    var inputIndex = 0;
+    this.addSniffer(WebInspector.ConsoleView.prototype, "addMessage",
+        function(commandResult) {
+            messagesCount++;
+            if (messagesCount === expectations.length) {
+                var messages = WebInspector.console.messages;
+                for (var i = 0; i < expectations; ++i) {
+                    var elem = messages[i++].toMessageElement();
+                    test.assertEquals(elem.textContent, expectations[i]);
+                }
+                test.releaseControl();
+            } else if (messagesCount % 2 === 0)
+                initEval(inputs[inputIndex++]);
+        }, true);
+
+    initEval(inputs[inputIndex++]);
+    this.takeControl();
+};
+
+
+/**
+ * Tests that Storage panel can be open and that local DOM storage is added
+ * to the panel.
+ */
+TestSuite.prototype.testShowStoragePanel = function()
+{
+    var test = this;
+    this.addSniffer(WebInspector.panels.storage, "addDOMStorage",
+        function(storage) {
+            var orig = storage.getEntries;
+            storage.getEntries = function(callback) {
+                orig.call(this, function(entries) {
+                    callback(entries);
+                    test.releaseControl();
+                });
+            };
+            try {
+                WebInspector.currentPanel.selectDOMStorage(storage.id);
+                storage.getEntries = orig;
+            } catch (e) {
+                test.fail("Exception in selectDOMStorage: " + e);
+            }
+        });
+    this.showPanel("storage");
+
+    // Access localStorage so that it's pushed to the frontend.
+    this.evaluateInConsole_(
+        'setTimeout("localStorage.x = 10" , 0)',
+        function(resultText) {
+            test.assertTrue(!isNaN(resultText), "Failed to get timer id: " + resultText);
+        });
+
+    // Wait until DOM storage is added to the panel.
+    this.takeControl();
+};
+
+
+/**
+ * Test runner for the test suite.
+ */
+var uiTests = {};
+
+
+/**
+ * Run each test from the test suit on a fresh instance of the suite.
+ */
+uiTests.runAllTests = function()
+{
+    // For debugging purposes.
+    for (var name in TestSuite.prototype) {
+        if (name.substring(0, 4) === "test" && typeof TestSuite.prototype[name] === "function")
+            uiTests.runTest(name);
+    }
+};
+
+
+/**
+ * Run specified test on a fresh instance of the test suite.
+ * @param {string} name Name of a test method from TestSuite class.
+ */
+uiTests.runTest = function(name)
+{
+    new TestSuite().runTest(name);
+};
+
+
+}

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list