<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[173992] trunk</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/173992">173992</a></dd>
<dt>Author</dt> <dd>burg@cs.washington.edu</dd>
<dt>Date</dt> <dd>2014-09-25 19:29:50 -0700 (Thu, 25 Sep 2014)</dd>
</dl>
<h3>Log Message</h3>
<pre>Web Inspector: FunctionCall timeline records omit profile data if the debugger has paused
https://bugs.webkit.org/show_bug.cgi?id=136805
Reviewed by Timothy Hatcher.
Source/WebCore:
TimelineAgent was mismanaging its call stack depth counter, which caused nested FunctionCall
records to steal the parent FunctionCall's captured profile in the child's didCallFunction().
Thus, the top FunctionCall node had no profile data and nested FunctionCall nodes each had
their own profiles. The frontend expected just one profile, so it didn't show anything when
it couldn't be found.
Test: inspector/timeline/debugger-paused-while-recording.html
* inspector/InspectorTimelineAgent.cpp: Rename m_recordingProfileDepth to m_callStackDepth.
(WebCore::InspectorTimelineAgent::willCallFunction): Fix the call stack depth management.
(WebCore::InspectorTimelineAgent::didCallFunction):
(WebCore::InspectorTimelineAgent::willEvaluateScript):
(WebCore::InspectorTimelineAgent::didEvaluateScript):
(WebCore::InspectorTimelineAgent::InspectorTimelineAgent):
* inspector/InspectorTimelineAgent.h:
Source/WebInspectorUI:
* UserInterface/Test.html: Add missing include for ScopeChainNode.js.
LayoutTests:
Add a test to see that script timeline records contain profiles even when
the debugger pauses during timeline capturing.
* inspector/timeline/debugger-paused-while-recording-expected.txt: Added.
* inspector/timeline/debugger-paused-while-recording.html: Added.
* inspector/timeline/resources/timeline-helper.js: Added.
(callFunction):
(hook):</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreinspectorInspectorTimelineAgentcpp">trunk/Source/WebCore/inspector/InspectorTimelineAgent.cpp</a></li>
<li><a href="#trunkSourceWebCoreinspectorInspectorTimelineAgenth">trunk/Source/WebCore/inspector/InspectorTimelineAgent.h</a></li>
<li><a href="#trunkSourceWebInspectorUIChangeLog">trunk/Source/WebInspectorUI/ChangeLog</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceTesthtml">trunk/Source/WebInspectorUI/UserInterface/Test.html</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsinspectortimelinedebuggerpausedwhilerecordingexpectedtxt">trunk/LayoutTests/inspector/timeline/debugger-paused-while-recording-expected.txt</a></li>
<li><a href="#trunkLayoutTestsinspectortimelinedebuggerpausedwhilerecordinghtml">trunk/LayoutTests/inspector/timeline/debugger-paused-while-recording.html</a></li>
<li><a href="#trunkLayoutTestsinspectortimelineresourcestimelinehelperjs">trunk/LayoutTests/inspector/timeline/resources/timeline-helper.js</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (173991 => 173992)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2014-09-26 02:20:05 UTC (rev 173991)
+++ trunk/LayoutTests/ChangeLog        2014-09-26 02:29:50 UTC (rev 173992)
</span><span class="lines">@@ -1,5 +1,21 @@
</span><span class="cx"> 2014-09-25 Brian J. Burg <burg@cs.washington.edu>
</span><span class="cx">
</span><ins>+ Web Inspector: FunctionCall timeline records omit profile data if the debugger has paused
+ https://bugs.webkit.org/show_bug.cgi?id=136805
+
+ Reviewed by Timothy Hatcher.
+
+ Add a test to see that script timeline records contain profiles even when
+ the debugger pauses during timeline capturing.
+
+ * inspector/timeline/debugger-paused-while-recording-expected.txt: Added.
+ * inspector/timeline/debugger-paused-while-recording.html: Added.
+ * inspector/timeline/resources/timeline-helper.js: Added.
+ (callFunction):
+ (hook):
+
+2014-09-25 Brian J. Burg <burg@cs.washington.edu>
+
</ins><span class="cx"> StorageTracker::deleteOrigin being called off the main thread (ASSERTs in inspector/test-harness-trivially-works.html test)
</span><span class="cx"> https://bugs.webkit.org/show_bug.cgi?id=129642
</span><span class="cx">
</span></span></pre></div>
<a id="trunkLayoutTestsinspectortimelinedebuggerpausedwhilerecordingexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/inspector/timeline/debugger-paused-while-recording-expected.txt (0 => 173992)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/inspector/timeline/debugger-paused-while-recording-expected.txt         (rev 0)
+++ trunk/LayoutTests/inspector/timeline/debugger-paused-while-recording-expected.txt        2014-09-26 02:29:50 UTC (rev 173992)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+Testing that profiling data is correctly generated and attached to Timeline records when the debugger pauses and resumes while capturing timelines.
+
+Added a breakpoint inside hook().
+Debugger paused; resuming...
+Debugger resumed; stopping timeline capture.
+Timeline capturing stopped. Inspecting the active recording....
+TimerFired timeline record has profile attached: TRUE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsinspectortimelinedebuggerpausedwhilerecordinghtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/inspector/timeline/debugger-paused-while-recording.html (0 => 173992)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/inspector/timeline/debugger-paused-while-recording.html         (rev 0)
+++ trunk/LayoutTests/inspector/timeline/debugger-paused-while-recording.html        2014-09-26 02:29:50 UTC (rev 173992)
</span><span class="lines">@@ -0,0 +1,82 @@
</span><ins>+<!doctype html>
+<html>
+<head>
+<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'">
+<script type="text/javascript" src="../../http/tests/inspector/inspector-test.js"></script>
+<script type="text/javascript" src="./resources/timeline-helper.js"></script>
+<script>
+function installTimer()
+{
+ setTimeout(function() {
+ callFunction(mul, add(1, 3), 3);
+ hook();
+ });
+}
+
+function add(a, b)
+{
+ InspectorTestProxy.addResult("Calling add(): " + a + " + " + b);
+ return a + b;
+}
+
+function mul(a, b)
+{
+ InspectorTestProxy.addResult("Calling mul(): " + a + " * " + b);
+ return a * b;
+}
+
+function test()
+{
+ // First, set up the breakpoint, start timeline capturing, and trigger execution of installTimer().
+ WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, function(event) {
+ var scriptObject = event.data.script;
+
+ if (!/timeline-helper\.js$/.test(scriptObject.url))
+ return;
+
+ var location = scriptObject.createSourceCodeLocation(17, 0); // Inside timeline-helper.js:hook()
+ var breakpoint = new WebInspector.Breakpoint(location);
+ WebInspector.debuggerManager.addBreakpoint(breakpoint);
+ InspectorTest.addResult("Added a breakpoint inside hook().")
+
+ WebInspector.timelineManager.startCapturing();
+ InspectorTest.evaluateInPage("installTimer()");
+ });
+
+ // Second, the debugger will pause during timeline capturing. Resume, then stop timeline capturing.
+ WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.Paused, function(event) {
+ InspectorTest.addResult("Debugger paused; resuming...");
+
+ WebInspector.debuggerManager.resume().then(function() {
+ InspectorTest.addResult("Debugger resumed; stopping timeline capture.");
+ WebInspector.timelineManager.stopCapturing();
+ })
+ });
+
+ // When timeline capturing stops, inspect the resulting timeline records for a profile.
+ WebInspector.timelineManager.addEventListener(WebInspector.TimelineManager.Event.CapturingStopped, function(event) {
+ var recording = WebInspector.timelineManager.activeRecording;
+ var scriptTimeline = recording.timelines.get(WebInspector.TimelineRecord.Type.Script);
+ console.assert(scriptTimeline);
+
+ InspectorTest.addResult("Timeline capturing stopped. Inspecting the active recording....");
+
+ for (var record of scriptTimeline.records) {
+ if (record.eventType !== WebInspector.ScriptTimelineRecord.EventType.TimerFired)
+ continue;
+
+ var result = record.profile ? "TRUE" : "FALSE";
+ InspectorTest.addResult("TimerFired timeline record has profile attached: " + result);
+ }
+
+ InspectorTest.completeTest();
+ });
+
+ InspectorTest.reloadPage();
+}
+</script>
+</head>
+<body onload="runTest()">
+ <p>Testing that profiling data is correctly generated and attached to Timeline records when the debugger pauses and resumes while capturing timelines.</p>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkLayoutTestsinspectortimelineresourcestimelinehelperjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/inspector/timeline/resources/timeline-helper.js (0 => 173992)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/inspector/timeline/resources/timeline-helper.js         (rev 0)
+++ trunk/LayoutTests/inspector/timeline/resources/timeline-helper.js        2014-09-26 02:29:50 UTC (rev 173992)
</span><span class="lines">@@ -0,0 +1,19 @@
</span><ins>+// WARNING: some tests blindly set breakpoints in this file by line number.
+// So, if you modify the code, make sure to adjust any createSourceCodeLocation
+// calls from tests in the ../ directory. Callsites should include a description
+// of the function/statement to set a breakpoint at, so that it's easy to fix them.
+
+function callFunction(fn)
+{
+ if (!(fn instanceof Function))
+ return;
+
+ var argsArray = Array.prototype.slice.call(arguments);
+ Array.prototype.splice.call(argsArray, 0, 1);
+ fn.call(this, argsArray);
+}
+
+function hook()
+{
+ return 42;
+}
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (173991 => 173992)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-09-26 02:20:05 UTC (rev 173991)
+++ trunk/Source/WebCore/ChangeLog        2014-09-26 02:29:50 UTC (rev 173992)
</span><span class="lines">@@ -1,5 +1,28 @@
</span><span class="cx"> 2014-09-25 Brian J. Burg <burg@cs.washington.edu>
</span><span class="cx">
</span><ins>+ Web Inspector: FunctionCall timeline records omit profile data if the debugger has paused
+ https://bugs.webkit.org/show_bug.cgi?id=136805
+
+ Reviewed by Timothy Hatcher.
+
+ TimelineAgent was mismanaging its call stack depth counter, which caused nested FunctionCall
+ records to steal the parent FunctionCall's captured profile in the child's didCallFunction().
+ Thus, the top FunctionCall node had no profile data and nested FunctionCall nodes each had
+ their own profiles. The frontend expected just one profile, so it didn't show anything when
+ it couldn't be found.
+
+ Test: inspector/timeline/debugger-paused-while-recording.html
+
+ * inspector/InspectorTimelineAgent.cpp: Rename m_recordingProfileDepth to m_callStackDepth.
+ (WebCore::InspectorTimelineAgent::willCallFunction): Fix the call stack depth management.
+ (WebCore::InspectorTimelineAgent::didCallFunction):
+ (WebCore::InspectorTimelineAgent::willEvaluateScript):
+ (WebCore::InspectorTimelineAgent::didEvaluateScript):
+ (WebCore::InspectorTimelineAgent::InspectorTimelineAgent):
+ * inspector/InspectorTimelineAgent.h:
+
+2014-09-25 Brian J. Burg <burg@cs.washington.edu>
+
</ins><span class="cx"> StorageTracker::deleteOrigin being called off the main thread (ASSERTs in inspector/test-harness-trivially-works.html test)
</span><span class="cx"> https://bugs.webkit.org/show_bug.cgi?id=129642
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceWebCoreinspectorInspectorTimelineAgentcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/inspector/InspectorTimelineAgent.cpp (173991 => 173992)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/inspector/InspectorTimelineAgent.cpp        2014-09-26 02:20:05 UTC (rev 173991)
+++ trunk/Source/WebCore/inspector/InspectorTimelineAgent.cpp        2014-09-26 02:29:50 UTC (rev 173992)
</span><span class="lines">@@ -231,19 +231,19 @@
</span><span class="cx"> {
</span><span class="cx"> pushCurrentRecord(TimelineRecordFactory::createFunctionCallData(scriptName, scriptLine), TimelineRecordType::FunctionCall, true, frame);
</span><span class="cx">
</span><del>- if (frame && !m_recordingProfileDepth) {
- ++m_recordingProfileDepth;
</del><ins>+ if (frame && !m_callStackDepth)
</ins><span class="cx"> startProfiling(frame, ASCIILiteral("Timeline FunctionCall"));
</span><del>- }
</del><ins>+
+ ++m_callStackDepth;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void InspectorTimelineAgent::didCallFunction(Frame* frame)
</span><span class="cx"> {
</span><del>- if (frame && m_recordingProfileDepth) {
- --m_recordingProfileDepth;
- ASSERT(m_recordingProfileDepth >= 0);
</del><ins>+ if (frame && m_callStackDepth) {
+ --m_callStackDepth;
+ ASSERT(m_callStackDepth >= 0);
</ins><span class="cx">
</span><del>- if (!m_recordingProfileDepth) {
</del><ins>+ if (!m_callStackDepth) {
</ins><span class="cx"> if (m_recordStack.isEmpty())
</span><span class="cx"> return;
</span><span class="cx">
</span><span class="lines">@@ -405,19 +405,19 @@
</span><span class="cx"> {
</span><span class="cx"> pushCurrentRecord(TimelineRecordFactory::createEvaluateScriptData(url, lineNumber), TimelineRecordType::EvaluateScript, true, frame);
</span><span class="cx">
</span><del>- if (frame && !m_recordingProfileDepth) {
- ++m_recordingProfileDepth;
</del><ins>+ if (frame && !m_callStackDepth) {
+ ++m_callStackDepth;
</ins><span class="cx"> startProfiling(frame, ASCIILiteral("Timeline EvaluateScript"));
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void InspectorTimelineAgent::didEvaluateScript(Frame* frame)
</span><span class="cx"> {
</span><del>- if (frame && m_recordingProfileDepth) {
- --m_recordingProfileDepth;
- ASSERT(m_recordingProfileDepth >= 0);
</del><ins>+ if (frame && m_callStackDepth) {
+ --m_callStackDepth;
+ ASSERT(m_callStackDepth >= 0);
</ins><span class="cx">
</span><del>- if (!m_recordingProfileDepth) {
</del><ins>+ if (!m_callStackDepth) {
</ins><span class="cx"> if (m_recordStack.isEmpty())
</span><span class="cx"> return;
</span><span class="cx">
</span><span class="lines">@@ -691,10 +691,10 @@
</span><span class="cx"> , m_pageAgent(pageAgent)
</span><span class="cx"> , m_scriptDebugServer(nullptr)
</span><span class="cx"> , m_id(1)
</span><ins>+ , m_callStackDepth(0)
</ins><span class="cx"> , m_maxCallStackDepth(5)
</span><span class="cx"> , m_inspectorType(type)
</span><span class="cx"> , m_client(client)
</span><del>- , m_recordingProfileDepth(0)
</del><span class="cx"> , m_enabled(false)
</span><span class="cx"> , m_enabledFromFrontend(false)
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceWebCoreinspectorInspectorTimelineAgenth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/inspector/InspectorTimelineAgent.h (173991 => 173992)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/inspector/InspectorTimelineAgent.h        2014-09-26 02:20:05 UTC (rev 173991)
+++ trunk/Source/WebCore/inspector/InspectorTimelineAgent.h        2014-09-26 02:29:50 UTC (rev 173992)
</span><span class="lines">@@ -279,13 +279,13 @@
</span><span class="cx"> Vector<TimelineRecordEntry> m_recordStack;
</span><span class="cx">
</span><span class="cx"> int m_id;
</span><ins>+ int m_callStackDepth;
</ins><span class="cx"> int m_maxCallStackDepth;
</span><span class="cx"> InspectorType m_inspectorType;
</span><span class="cx"> InspectorClient* m_client;
</span><span class="cx">
</span><span class="cx"> Vector<TimelineRecordEntry> m_pendingConsoleProfileRecords;
</span><span class="cx">
</span><del>- int m_recordingProfileDepth;
</del><span class="cx"> bool m_enabled;
</span><span class="cx"> bool m_enabledFromFrontend;
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/ChangeLog (173991 => 173992)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/ChangeLog        2014-09-26 02:20:05 UTC (rev 173991)
+++ trunk/Source/WebInspectorUI/ChangeLog        2014-09-26 02:29:50 UTC (rev 173992)
</span><span class="lines">@@ -1,5 +1,14 @@
</span><span class="cx"> 2014-09-25 Brian J. Burg <burg@cs.washington.edu>
</span><span class="cx">
</span><ins>+ Web Inspector: FunctionCall timeline records omit profile data if the debugger has paused
+ https://bugs.webkit.org/show_bug.cgi?id=136805
+
+ Reviewed by Timothy Hatcher.
+
+ * UserInterface/Test.html: Add missing include for ScopeChainNode.js.
+
+2014-09-25 Brian J. Burg <burg@cs.washington.edu>
+
</ins><span class="cx"> Web Inspector: sort probe details sidebar sections by source code location string
</span><span class="cx"> https://bugs.webkit.org/show_bug.cgi?id=137080
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceTesthtml"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Test.html (173991 => 173992)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Test.html        2014-09-26 02:20:05 UTC (rev 173991)
+++ trunk/Source/WebInspectorUI/UserInterface/Test.html        2014-09-26 02:29:50 UTC (rev 173992)
</span><span class="lines">@@ -103,6 +103,7 @@
</span><span class="cx"> <script src="Models/ResourceCollection.js"></script>
</span><span class="cx"> <script src="Models/ResourceTimelineRecord.js"></script>
</span><span class="cx"> <script src="Models/Revision.js"></script>
</span><ins>+ <script src="Models/ScopeChainNode.js"></script>
</ins><span class="cx"> <script src="Models/Script.js"></script>
</span><span class="cx"> <script src="Models/ScriptSyntaxTree.js"></script>
</span><span class="cx"> <script src="Models/ScriptTimelineRecord.js"></script>
</span></span></pre>
</div>
</div>
</body>
</html>