<!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>[198462] trunk/Websites/perf.webkit.org</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/198462">198462</a></dd>
<dt>Author</dt> <dd>rniwa@webkit.org</dd>
<dt>Date</dt> <dd>2016-03-18 19:17:48 -0700 (Fri, 18 Mar 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Add unit tests for measurement-set.js and measurement-adapter.js
https://bugs.webkit.org/show_bug.cgi?id=155673

Reviewed by Darin Adler.

Added mocha unit tests for MeasurementSet and MeasurementAdapter classes along with the necessary
refactoring to run these tests in node.

getJSON and getJSONStatus are now under RemoteAPI so that unit tests can mock them.

Removed the dependency on v2 UI's TimeSeries and Measurement class by adding a new implementation
of TimeSeries in v3 and removing the dependency on Measurement in chart-pane-status-view.js with
new helper methods on Build and CommitLog.

Many js files now use 'use strict' (node doesn't support class syntax in non-strict mode) and
module.exports to export symbols in node's require function.

* public/v3/index.html:
* public/v3/main.js:
* public/v3/models/analysis-results.js:
(AnalysisResults.fetch):
* public/v3/models/analysis-task.js:
(AnalysisTask.fetchAll):
* public/v3/models/builder.js:
(Build):
(Build.prototype.builder): Added. Used by ChartPaneStatusView.
(Build.prototype.buildNumber): Ditto.
(Build.prototype.buildTime): Ditto.
* public/v3/models/commit-log.js:
(CommitLog.prototype.diff): Ditto.
(CommitLog.fetchBetweenRevisions):
* public/v3/models/data-model.js:
(DataModelObject.cachedFetch):
* public/v3/models/measurement-adaptor.js:
(MeasurementAdaptor.prototype.applyToAnalysisResults): Renamed from adoptToAnalysisResults.
(MeasurementAdaptor.prototype.applyTo): Renamed from adoptToSeries. Now shares a lot more
code with applyToAnalysisResults. The code to set 'series' and 'seriesIndex' has been moved
to TimeSeries.append. 'measurement' is no longer needed as this patch removes its only use
in ChartPaneStatusView.
* public/v3/models/measurement-cluster.js:
(MeasurementCluster.prototype.addToSeries): Use TimeSeries.append instead of directly mutating
series._series.
* public/v3/models/measurement-set.js:
(Array.prototype.includes): Added a polyfill for node.
(MeasurementSet.prototype._fetchSecondaryClusters): Removed a bogus assertion. When fetchBetween
is called with a mixture of clusters that have been fetched and not fetched, this assertion fails.
(MeasurementSet.prototype._fetch):
(TimeSeries.prototype.findById): Moved to time-series.js.
(TimeSeries.prototype.dataBetweenPoints): Ditto.
(TimeSeries.prototype.firstPoint): Ditto.
(TimeSeries.prototype.fetchedTimeSeries): Moved the code to extend the last point to TimeSeries'
extendToFuture.
* public/v3/models/repository.js:
* public/v3/models/root-set.js:
(MeasurementRootSet): Ignore repositories that had not been defined (e.g. it could be added after
manifest.json had been downloaded but before a given root set is created for an A/B testing).
* public/v3/models/time-series.js:
(TimeSeries): Added.
(TimeSeries.prototype.append): Added.
(TimeSeries.prototype.extendToFuture): Added.
(TimeSeries.prototype.firstPoint): Moved from measurement-set.js.
(TimeSeries.prototype.lastPoint): Added.
(TimeSeries.prototype.previousPoint): Added.
(TimeSeries.prototype.nextPoint): Added.
(TimeSeries.prototype.findPointByIndex): Added.
(TimeSeries.prototype.findById): Moved from measurement-set.js.
(TimeSeries.prototype.findPointAfterTime): Added.
(TimeSeries.prototype.dataBetweenPoints): Moved from measurement-set.js.
* public/v3/pages/chart-pane-status-view.js:
(ChartPaneStatusView.prototype.render): Use newly added helper functions on Build.
(ChartPaneStatusView.prototype._formatTime): Added.
(ChartPaneStatusView.prototype.setCurrentRepository):
(ChartPaneStatusView.prototype.computeChartStatusLabels): Rewrote the code using RootSet object on
currentPoint and previousPoint instead of Measurement class from v2 UI. Also sort the results using
sortByNamePreferringOnesWithURL.
* public/v3/remote.js:
(RemoteAPI.getJSON): Moved under RemoteAPI.
(RemoteAPI.getJSONWithStatus): Ditto.
(PrivilegedAPI):
(PrivilegedAPI.requestCSRFToken):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkWebsitesperfwebkitorgChangeLog">trunk/Websites/perf.webkit.org/ChangeLog</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3indexhtml">trunk/Websites/perf.webkit.org/public/v3/index.html</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3mainjs">trunk/Websites/perf.webkit.org/public/v3/main.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3modelsanalysisresultsjs">trunk/Websites/perf.webkit.org/public/v3/models/analysis-results.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3modelsanalysistaskjs">trunk/Websites/perf.webkit.org/public/v3/models/analysis-task.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3modelsbuilderjs">trunk/Websites/perf.webkit.org/public/v3/models/builder.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3modelscommitlogjs">trunk/Websites/perf.webkit.org/public/v3/models/commit-log.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3modelsdatamodeljs">trunk/Websites/perf.webkit.org/public/v3/models/data-model.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3modelsmeasurementadaptorjs">trunk/Websites/perf.webkit.org/public/v3/models/measurement-adaptor.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3modelsmeasurementclusterjs">trunk/Websites/perf.webkit.org/public/v3/models/measurement-cluster.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3modelsmeasurementsetjs">trunk/Websites/perf.webkit.org/public/v3/models/measurement-set.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3modelsrepositoryjs">trunk/Websites/perf.webkit.org/public/v3/models/repository.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3modelsrootsetjs">trunk/Websites/perf.webkit.org/public/v3/models/root-set.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3pageschartpanestatusviewjs">trunk/Websites/perf.webkit.org/public/v3/pages/chart-pane-status-view.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3remotejs">trunk/Websites/perf.webkit.org/public/v3/remote.js</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3modelstimeseriesjs">trunk/Websites/perf.webkit.org/public/v3/models/time-series.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkWebsitesperfwebkitorgChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/ChangeLog (198461 => 198462)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/ChangeLog        2016-03-19 01:37:45 UTC (rev 198461)
+++ trunk/Websites/perf.webkit.org/ChangeLog        2016-03-19 02:17:48 UTC (rev 198462)
</span><span class="lines">@@ -1,3 +1,86 @@
</span><ins>+2016-03-18  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
+
+        Add unit tests for measurement-set.js and measurement-adapter.js
+        https://bugs.webkit.org/show_bug.cgi?id=155673
+
+        Reviewed by Darin Adler.
+
+        Added mocha unit tests for MeasurementSet and MeasurementAdapter classes along with the necessary
+        refactoring to run these tests in node.
+
+        getJSON and getJSONStatus are now under RemoteAPI so that unit tests can mock them.
+
+        Removed the dependency on v2 UI's TimeSeries and Measurement class by adding a new implementation
+        of TimeSeries in v3 and removing the dependency on Measurement in chart-pane-status-view.js with
+        new helper methods on Build and CommitLog.
+
+        Many js files now use 'use strict' (node doesn't support class syntax in non-strict mode) and
+        module.exports to export symbols in node's require function.
+
+        * public/v3/index.html:
+        * public/v3/main.js:
+        * public/v3/models/analysis-results.js:
+        (AnalysisResults.fetch):
+        * public/v3/models/analysis-task.js:
+        (AnalysisTask.fetchAll):
+        * public/v3/models/builder.js:
+        (Build):
+        (Build.prototype.builder): Added. Used by ChartPaneStatusView.
+        (Build.prototype.buildNumber): Ditto.
+        (Build.prototype.buildTime): Ditto.
+        * public/v3/models/commit-log.js:
+        (CommitLog.prototype.diff): Ditto.
+        (CommitLog.fetchBetweenRevisions):
+        * public/v3/models/data-model.js:
+        (DataModelObject.cachedFetch):
+        * public/v3/models/measurement-adaptor.js:
+        (MeasurementAdaptor.prototype.applyToAnalysisResults): Renamed from adoptToAnalysisResults.
+        (MeasurementAdaptor.prototype.applyTo): Renamed from adoptToSeries. Now shares a lot more
+        code with applyToAnalysisResults. The code to set 'series' and 'seriesIndex' has been moved
+        to TimeSeries.append. 'measurement' is no longer needed as this patch removes its only use
+        in ChartPaneStatusView.
+        * public/v3/models/measurement-cluster.js:
+        (MeasurementCluster.prototype.addToSeries): Use TimeSeries.append instead of directly mutating
+        series._series.
+        * public/v3/models/measurement-set.js:
+        (Array.prototype.includes): Added a polyfill for node.
+        (MeasurementSet.prototype._fetchSecondaryClusters): Removed a bogus assertion. When fetchBetween
+        is called with a mixture of clusters that have been fetched and not fetched, this assertion fails.
+        (MeasurementSet.prototype._fetch):
+        (TimeSeries.prototype.findById): Moved to time-series.js.
+        (TimeSeries.prototype.dataBetweenPoints): Ditto.
+        (TimeSeries.prototype.firstPoint): Ditto.
+        (TimeSeries.prototype.fetchedTimeSeries): Moved the code to extend the last point to TimeSeries'
+        extendToFuture.
+        * public/v3/models/repository.js:
+        * public/v3/models/root-set.js:
+        (MeasurementRootSet): Ignore repositories that had not been defined (e.g. it could be added after
+        manifest.json had been downloaded but before a given root set is created for an A/B testing).
+        * public/v3/models/time-series.js:
+        (TimeSeries): Added.
+        (TimeSeries.prototype.append): Added.
+        (TimeSeries.prototype.extendToFuture): Added.
+        (TimeSeries.prototype.firstPoint): Moved from measurement-set.js.
+        (TimeSeries.prototype.lastPoint): Added.
+        (TimeSeries.prototype.previousPoint): Added.
+        (TimeSeries.prototype.nextPoint): Added.
+        (TimeSeries.prototype.findPointByIndex): Added.
+        (TimeSeries.prototype.findById): Moved from measurement-set.js.
+        (TimeSeries.prototype.findPointAfterTime): Added.
+        (TimeSeries.prototype.dataBetweenPoints): Moved from measurement-set.js.
+        * public/v3/pages/chart-pane-status-view.js:
+        (ChartPaneStatusView.prototype.render): Use newly added helper functions on Build.
+        (ChartPaneStatusView.prototype._formatTime): Added.
+        (ChartPaneStatusView.prototype.setCurrentRepository):
+        (ChartPaneStatusView.prototype.computeChartStatusLabels): Rewrote the code using RootSet object on
+        currentPoint and previousPoint instead of Measurement class from v2 UI. Also sort the results using
+        sortByNamePreferringOnesWithURL.
+        * public/v3/remote.js:
+        (RemoteAPI.getJSON): Moved under RemoteAPI.
+        (RemoteAPI.getJSONWithStatus): Ditto.
+        (PrivilegedAPI):
+        (PrivilegedAPI.requestCSRFToken):
+
</ins><span class="cx"> 2016-03-17  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Add unit tests for config.json and statistics.js
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3indexhtml"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/index.html (198461 => 198462)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/index.html        2016-03-19 01:37:45 UTC (rev 198461)
+++ trunk/Websites/perf.webkit.org/public/v3/index.html        2016-03-19 02:17:48 UTC (rev 198462)
</span><span class="lines">@@ -43,6 +43,7 @@
</span><span class="cx">         &lt;script src=&quot;instrumentation.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">         &lt;script src=&quot;remote.js&quot;&gt;&lt;/script&gt;
</span><span class="cx"> 
</span><ins>+        &lt;script src=&quot;models/time-series.js&quot;&gt;&lt;/script&gt;
</ins><span class="cx">         &lt;script src=&quot;models/measurement-adaptor.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">         &lt;script src=&quot;models/measurement-cluster.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">         &lt;script src=&quot;models/measurement-set.js&quot;&gt;&lt;/script&gt;
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3mainjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/main.js (198461 => 198462)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/main.js        2016-03-19 01:37:45 UTC (rev 198461)
+++ trunk/Websites/perf.webkit.org/public/v3/main.js        2016-03-19 02:17:48 UTC (rev 198462)
</span><span class="lines">@@ -56,8 +56,8 @@
</span><span class="cx"> 
</span><span class="cx"> function fetchManifest()
</span><span class="cx"> {
</span><del>-    return getJSON('../data/manifest.json').then(didFetchManifest, function () {
-        return getJSON('../api/manifest/').then(didFetchManifest, function (error) {
</del><ins>+    return RemoteAPI.getJSON('../data/manifest.json').then(didFetchManifest, function () {
+        return RemoteAPI.getJSON('../api/manifest/').then(didFetchManifest, function (error) {
</ins><span class="cx">             alert('Failed to load the site manifest: ' + error);
</span><span class="cx">         });
</span><span class="cx">     });
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3modelsanalysisresultsjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/models/analysis-results.js (198461 => 198462)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/models/analysis-results.js        2016-03-19 01:37:45 UTC (rev 198461)
+++ trunk/Websites/perf.webkit.org/public/v3/models/analysis-results.js        2016-03-19 02:17:48 UTC (rev 198462)
</span><span class="lines">@@ -26,14 +26,14 @@
</span><span class="cx">     static fetch(taskId)
</span><span class="cx">     {
</span><span class="cx">         taskId = parseInt(taskId);
</span><del>-        return getJSONWithStatus(`../api/measurement-set?analysisTask=${taskId}`).then(function (response) {
</del><ins>+        return RemoteAPI.getJSONWithStatus(`../api/measurement-set?analysisTask=${taskId}`).then(function (response) {
</ins><span class="cx"> 
</span><span class="cx">             Instrumentation.startMeasuringTime('AnalysisResults', 'fetch');
</span><span class="cx"> 
</span><span class="cx">             var adaptor = new MeasurementAdaptor(response['formatMap']);
</span><span class="cx">             var results = new AnalysisResults;
</span><span class="cx">             for (var rawMeasurement of response['measurements'])
</span><del>-                results.add(adaptor.adoptToAnalysisResults(rawMeasurement));
</del><ins>+                results.add(adaptor.applyToAnalysisResults(rawMeasurement));
</ins><span class="cx"> 
</span><span class="cx">             Instrumentation.endMeasuringTime('AnalysisResults', 'fetch');
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3modelsanalysistaskjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/models/analysis-task.js (198461 => 198462)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/models/analysis-task.js        2016-03-19 01:37:45 UTC (rev 198461)
+++ trunk/Websites/perf.webkit.org/public/v3/models/analysis-task.js        2016-03-19 02:17:48 UTC (rev 198462)
</span><span class="lines">@@ -207,7 +207,7 @@
</span><span class="cx">     static fetchAll()
</span><span class="cx">     {
</span><span class="cx">         if (!this._fetchAllPromise)
</span><del>-            this._fetchAllPromise = getJSONWithStatus('../api/analysis-tasks').then(this._constructAnalysisTasksFromRawData.bind(this));
</del><ins>+            this._fetchAllPromise = RemoteAPI.getJSONWithStatus('../api/analysis-tasks').then(this._constructAnalysisTasksFromRawData.bind(this));
</ins><span class="cx">         return this._fetchAllPromise;
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3modelsbuilderjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/models/builder.js (198461 => 198462)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/models/builder.js        2016-03-19 01:37:45 UTC (rev 198461)
+++ trunk/Websites/perf.webkit.org/public/v3/models/builder.js        2016-03-19 02:17:48 UTC (rev 198462)
</span><span class="lines">@@ -1,3 +1,4 @@
</span><ins>+'use strict';
</ins><span class="cx"> 
</span><span class="cx"> class Builder extends LabeledObject {
</span><span class="cx">     constructor(id, object)
</span><span class="lines">@@ -15,14 +16,23 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> class Build extends DataModelObject {
</span><del>-    constructor(id, builder, buildNumber)
</del><ins>+    constructor(id, builder, buildNumber, buildTime)
</ins><span class="cx">     {
</span><span class="cx">         console.assert(builder instanceof Builder);
</span><span class="cx">         super(id);
</span><span class="cx">         this._builder = builder;
</span><span class="cx">         this._buildNumber = buildNumber;
</span><ins>+        this._buildTime = new Date(buildTime);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    builder() { return this._builder; }
+    buildNumber() { return this._buildNumber; }
+    buildTime() { return this._buildTime; }
</ins><span class="cx">     label() { return `Build ${this._buildNumber} on ${this._builder.label()}`; }
</span><span class="cx">     url() { return this._builder.urlForBuild(this._buildNumber); }
</span><span class="cx"> }
</span><ins>+
+if (typeof module != 'undefined') {
+    module.exports.Builder = Builder;
+    module.exports.Build = Build;
+}
</ins></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3modelscommitlogjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/models/commit-log.js (198461 => 198462)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/models/commit-log.js        2016-03-19 01:37:45 UTC (rev 198461)
+++ trunk/Websites/perf.webkit.org/public/v3/models/commit-log.js        2016-03-19 02:17:48 UTC (rev 198462)
</span><span class="lines">@@ -1,3 +1,4 @@
</span><ins>+'use strict';
</ins><span class="cx"> 
</span><span class="cx"> class CommitLog extends DataModelObject {
</span><span class="cx">     constructor(id, rawData)
</span><span class="lines">@@ -56,6 +57,29 @@
</span><span class="cx">     }
</span><span class="cx">     title() { return this._repository.name() + ' at ' + this.label(); }
</span><span class="cx"> 
</span><ins>+    diff(previousCommit)
+    {
+        if (this == previousCommit)
+            previousCommit = null;
+
+        var repository = this._repository;
+        if (!previousCommit)
+            return {from: null, to: this.revision(), repository: repository, label: this.label(), url: this.url()};
+
+        var to = this.revision();
+        var from = previousCommit.revision();
+        var label = null;
+        if (parseInt(to) == to) { // e.g. r12345.
+            from = parseInt(from) + 1;
+            label = `r${from}-r${this.revision()}`;
+        } else if (to.length == 40) { // e.g. git hash
+            label = `${from}..${to}`;
+        } else
+            label = `${from} - ${to}`;
+
+        return {from: from, to: to, repository: repository, label: label, url: repository.urlForRevisionRange(from, to)};
+    }
+
</ins><span class="cx">     static fetchBetweenRevisions(repository, from, to)
</span><span class="cx">     {
</span><span class="cx">         var params = [];
</span><span class="lines">@@ -74,7 +98,7 @@
</span><span class="cx">             return new Promise(function (resolve) { resolve(cachedLogs); });
</span><span class="cx"> 
</span><span class="cx">         var self = this;
</span><del>-        return getJSONWithStatus(url).then(function (data) {
</del><ins>+        return RemoteAPI.getJSONWithStatus(url).then(function (data) {
</ins><span class="cx">             var commits = data['commits'].map(function (rawData) { return CommitLog.ensureSingleton(repository, rawData); });
</span><span class="cx">             self._cacheCommitLogs(repository, from, to, commits);
</span><span class="cx">             return commits;
</span><span class="lines">@@ -101,3 +125,6 @@
</span><span class="cx">         this._caches[repository.id()][from + '|' + to] = logs;
</span><span class="cx">     }
</span><span class="cx"> }
</span><ins>+
+if (typeof module != 'undefined')
+    module.exports.CommitLog = CommitLog;
</ins></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3modelsdatamodeljs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/models/data-model.js (198461 => 198462)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/models/data-model.js        2016-03-19 01:37:45 UTC (rev 198461)
+++ trunk/Websites/perf.webkit.org/public/v3/models/data-model.js        2016-03-19 02:17:48 UTC (rev 198462)
</span><span class="lines">@@ -1,3 +1,4 @@
</span><ins>+'use strict';
</ins><span class="cx"> 
</span><span class="cx"> class DataModelObject {
</span><span class="cx">     constructor(id)
</span><span class="lines">@@ -66,11 +67,11 @@
</span><span class="cx">             path += '?' + query.join('&amp;');
</span><span class="cx"> 
</span><span class="cx">         if (noCache)
</span><del>-            return getJSONWithStatus(path);
</del><ins>+            return RemoteAPI.getJSONWithStatus(path);
</ins><span class="cx"> 
</span><span class="cx">         var cacheMap = this.ensureNamedStaticMap(DataModelObject.CacheMapSymbol);
</span><span class="cx">         if (!cacheMap[path])
</span><del>-            cacheMap[path] = getJSONWithStatus(path);
</del><ins>+            cacheMap[path] = RemoteAPI.getJSONWithStatus(path);
</ins><span class="cx"> 
</span><span class="cx">         return cacheMap[path];
</span><span class="cx">     }
</span><span class="lines">@@ -103,3 +104,8 @@
</span><span class="cx">     name() { return this._name; }
</span><span class="cx">     label() { return this.name(); }
</span><span class="cx"> }
</span><ins>+
+if (typeof module != 'undefined') {
+    module.exports.DataModelObject = DataModelObject;
+    module.exports.LabeledObject = LabeledObject;
+}
</ins></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3modelsmeasurementadaptorjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/models/measurement-adaptor.js (198461 => 198462)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/models/measurement-adaptor.js        2016-03-19 01:37:45 UTC (rev 198461)
+++ trunk/Websites/perf.webkit.org/public/v3/models/measurement-adaptor.js        2016-03-19 02:17:48 UTC (rev 198462)
</span><span class="lines">@@ -1,3 +1,4 @@
</span><ins>+'use strict';
</ins><span class="cx"> 
</span><span class="cx"> class MeasurementAdaptor {
</span><span class="cx">     constructor(formatMap)
</span><span class="lines">@@ -27,32 +28,38 @@
</span><span class="cx">         return row[this._idIndex];
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    adoptToAnalysisResults(row)
</del><ins>+    applyToAnalysisResults(row)
</ins><span class="cx">     {
</span><ins>+        var adaptedRow = this.applyTo(row);
+        adaptedRow.metricId = row[this._metricIndex];
+        adaptedRow.configType = row[this._configTypeIndex];
+        return adaptedRow;
+    }
+
+    applyTo(row)
+    {
</ins><span class="cx">         var id = row[this._idIndex];
</span><span class="cx">         var mean = row[this._meanIndex];
</span><span class="cx">         var sum = row[this._sumIndex];
</span><span class="cx">         var squareSum = row[this._squareSumIndex];
</span><del>-        var iterationCount = row[this._countIndex];
</del><span class="cx">         var revisionList = row[this._revisionsIndex];
</span><span class="cx">         var buildId = row[this._buildIndex];
</span><del>-        var metricId = row[this._metricIndex];
-        var configType = row[this._configTypeIndex];
</del><ins>+        var builderId = row[this._builderIndex];
+        var buildNumber = row[this._buildNumberIndex];
+        var buildTime = row[this._buildTimeIndex];
</ins><span class="cx">         var self = this;
</span><span class="cx">         return {
</span><span class="cx">             id: id,
</span><span class="cx">             buildId: buildId,
</span><del>-            metricId: metricId,
-            configType: configType,
</del><ins>+            metricId: null,
+            configType: null,
</ins><span class="cx">             rootSet: function () { return MeasurementRootSet.ensureSingleton(id, revisionList); },
</span><del>-            build: function () {
-                var builder = Builder.findById(row[self._builderIndex]);
-                return new Build(id, builder, row[self._buildNumberIndex]);
-            },
</del><ins>+            build: function () { return new Build(buildId, Builder.findById(builderId), buildNumber, buildTime); },
+            time: row[this._commitTimeIndex],
</ins><span class="cx">             value: mean,
</span><span class="cx">             sum: sum,
</span><del>-            squareSum,
-            iterationCount: iterationCount,
</del><ins>+            squareSum: squareSum,
+            iterationCount: row[this._countIndex],
</ins><span class="cx">             interval: MeasurementAdaptor.computeConfidenceInterval(row[this._countIndex], mean, sum, squareSum)
</span><span class="cx">         };
</span><span class="cx">     }
</span><span class="lines">@@ -79,45 +86,12 @@
</span><span class="cx">         return { value: mean, interval: interval };
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    adoptToSeries(row, series, seriesIndex)
-    {
-        var id = row[this._idIndex];
-        var mean = row[this._meanIndex];
-        var sum = row[this._sumIndex];
-        var squareSum = row[this._squareSumIndex];
-        var revisionList = row[this._revisionsIndex];
-        var self = this;
-        return {
-            id: id,
-            measurement: function () {
-                // Create a new Measurement class that doesn't require mimicking what runs.php generates.
-                var revisionsMap = {};
-                for (var revisionRow of revisionList)
-                    revisionsMap[revisionRow[0]] = revisionRow.slice(1);
-                return new Measurement({
-                    id: id,
-                    mean: mean,
-                    sum: sum,
-                    squareSum: squareSum,
-                    revisions: revisionsMap,
-                    build: row[self._buildIndex],
-                    buildTime: row[self._buildTimeIndex],
-                    buildNumber: row[self._buildNumberIndex],
-                    builder: row[self._builderIndex],
-                });
-            },
-            rootSet: function () { return MeasurementRootSet.ensureSingleton(id, revisionList); },
-            series: series,
-            seriesIndex: seriesIndex,
-            time: row[this._commitTimeIndex],
-            value: mean,
-            interval: MeasurementAdaptor.computeConfidenceInterval(row[this._countIndex], mean, sum, squareSum)
-        };
-    }
-
</del><span class="cx">     static computeConfidenceInterval(iterationCount, mean, sum, squareSum)
</span><span class="cx">     {
</span><span class="cx">         var delta = Statistics.confidenceIntervalDelta(0.95, iterationCount, sum, squareSum);
</span><span class="cx">         return isNaN(delta) ? null : [mean - delta, mean + delta];
</span><span class="cx">     }
</span><span class="cx"> }
</span><ins>+
+if (typeof module != 'undefined')
+    module.exports.MeasurementAdaptor = MeasurementAdaptor;
</ins></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3modelsmeasurementclusterjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/models/measurement-cluster.js (198461 => 198462)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/models/measurement-cluster.js        2016-03-19 01:37:45 UTC (rev 198461)
+++ trunk/Websites/perf.webkit.org/public/v3/models/measurement-cluster.js        2016-03-19 02:17:48 UTC (rev 198462)
</span><span class="lines">@@ -1,3 +1,4 @@
</span><ins>+'use strict';
</ins><span class="cx"> 
</span><span class="cx"> class MeasurementCluster {
</span><span class="cx">     constructor(response)
</span><span class="lines">@@ -25,7 +26,10 @@
</span><span class="cx"> 
</span><span class="cx">             idMap[id] = true;
</span><span class="cx"> 
</span><del>-            series._series.push(self._adaptor.adoptToSeries(row, series, series._series.length));
</del><ins>+            series.append(self._adaptor.applyTo(row));
</ins><span class="cx">         });
</span><span class="cx">     }
</span><span class="cx"> }
</span><ins>+
+if (typeof module != 'undefined')
+    module.exports.MeasurementCluster = MeasurementCluster;
</ins></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3modelsmeasurementsetjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/models/measurement-set.js (198461 => 198462)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/models/measurement-set.js        2016-03-19 01:37:45 UTC (rev 198461)
+++ trunk/Websites/perf.webkit.org/public/v3/models/measurement-set.js        2016-03-19 02:17:48 UTC (rev 198462)
</span><span class="lines">@@ -1,4 +1,8 @@
</span><ins>+'use strict';
</ins><span class="cx"> 
</span><ins>+if (!Array.prototype.includes)
+    Array.prototype.includes = function (value) { return this.indexOf(value) &gt;= 0; }
+
</ins><span class="cx"> class MeasurementSet {
</span><span class="cx">     constructor(platformId, metricId, lastModified)
</span><span class="cx">     {
</span><span class="lines">@@ -96,10 +100,8 @@
</span><span class="cx">             else if (!callbackList.includes(callback))
</span><span class="cx">                 callbackList.push(callback);
</span><span class="cx"> 
</span><del>-            if (shouldStartFetch) {
-                console.assert(!shouldInvokeCallackNow);
</del><ins>+            if (shouldStartFetch)
</ins><span class="cx">                 this._fetch(endTime, true);
</span><del>-            }
</del><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (shouldInvokeCallackNow)
</span><span class="lines">@@ -121,7 +123,7 @@
</span><span class="cx"> 
</span><span class="cx">         var self = this;
</span><span class="cx"> 
</span><del>-        return getJSONWithStatus(url).then(function (data) {
</del><ins>+        return RemoteAPI.getJSONWithStatus(url).then(function (data) {
</ins><span class="cx">             if (!clusterEndTime &amp;&amp; useCache &amp;&amp; +data['lastModified'] &lt; self._lastModified)
</span><span class="cx">                 self._fetch(clusterEndTime, false);
</span><span class="cx">             else
</span><span class="lines">@@ -218,17 +220,8 @@
</span><span class="cx">         for (var cluster of this._sortedClusters)
</span><span class="cx">             cluster.addToSeries(series, configType, includeOutliers, idMap);
</span><span class="cx"> 
</span><del>-        if (extendToFuture &amp;&amp; series._series.length) {
-            var lastPoint = series._series[series._series.length - 1];
-            series._series.push({
-                series: series,
-                seriesIndex: series._series.length,
-                measurement: null,
-                time: Date.now() + 365 * 24 * 3600 * 1000,
-                value: lastPoint.value,
-                interval: lastPoint.interval,
-            });
-        }
</del><ins>+        if (extendToFuture)
+            series.extendToFuture();
</ins><span class="cx"> 
</span><span class="cx">         Instrumentation.endMeasuringTime('MeasurementSet', 'fetchedTimeSeries');
</span><span class="cx"> 
</span><span class="lines">@@ -236,25 +229,5 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-TimeSeries.prototype.findById = function (id)
-{
-    return this._series.find(function (point) { return point.id == id });
-}
-
-TimeSeries.prototype.dataBetweenPoints = function (firstPoint, lastPoint)
-{
-    var data = this._series;
-    var filteredData = [];
-    for (var i = firstPoint.seriesIndex; i &lt;= lastPoint.seriesIndex; i++) {
-        if (!data[i].markedOutlier)
-            filteredData.push(data[i]);
-    }
-    return filteredData;
-}
-
-TimeSeries.prototype.firstPoint = function ()
-{
-    if (!this._series || !this._series.length)
-        return null;
-    return this._series[0];
-}
</del><ins>+if (typeof module != 'undefined')
+    module.exports.MeasurementSet = MeasurementSet;
</ins></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3modelsrepositoryjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/models/repository.js (198461 => 198462)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/models/repository.js        2016-03-19 01:37:45 UTC (rev 198461)
+++ trunk/Websites/perf.webkit.org/public/v3/models/repository.js        2016-03-19 02:17:48 UTC (rev 198462)
</span><span class="lines">@@ -1,3 +1,4 @@
</span><ins>+'use strict';
</ins><span class="cx"> 
</span><span class="cx"> class Repository extends LabeledObject {
</span><span class="cx">     constructor(id, object)
</span><span class="lines">@@ -36,3 +37,6 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> }
</span><ins>+
+if (typeof module != 'undefined')
+    module.exports.Repository = Repository;
</ins></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3modelsrootsetjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/models/root-set.js (198461 => 198462)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/models/root-set.js        2016-03-19 01:37:45 UTC (rev 198461)
+++ trunk/Websites/perf.webkit.org/public/v3/models/root-set.js        2016-03-19 02:17:48 UTC (rev 198462)
</span><span class="lines">@@ -1,3 +1,4 @@
</span><ins>+'use strict';
</ins><span class="cx"> 
</span><span class="cx"> class RootSet extends DataModelObject {
</span><span class="cx"> 
</span><span class="lines">@@ -75,6 +76,8 @@
</span><span class="cx">         for (var values of revisionList) {
</span><span class="cx">             var repositoryId = values[0];
</span><span class="cx">             var repository = Repository.findById(repositoryId);
</span><ins>+            if (!repository)
+                continue;
</ins><span class="cx"> 
</span><span class="cx">             this._repositoryToCommitMap[repositoryId] = CommitLog.ensureSingleton(repository, {revision: values[1], time: values[2]});
</span><span class="cx">             this._repositories.push(repository);
</span><span class="lines">@@ -106,3 +109,8 @@
</span><span class="cx"> 
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+if (typeof module != 'undefined') {
+    module.exports.RootSet = RootSet;
+    module.exports.MeasurementRootSet = MeasurementRootSet;
+    module.exports.CustomRootSet = CustomRootSet;
+}
</ins></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3modelstimeseriesjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/perf.webkit.org/public/v3/models/time-series.js (0 => 198462)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/models/time-series.js                                (rev 0)
+++ trunk/Websites/perf.webkit.org/public/v3/models/time-series.js        2016-03-19 02:17:48 UTC (rev 198462)
</span><span class="lines">@@ -0,0 +1,73 @@
</span><ins>+
+// v3 UI still relies on RunsData for associating metrics with units.
+// Use declartive syntax once that dependency has been removed.
+TimeSeries = class {
+    constructor()
+    {
+        this._data = [];
+    }
+
+    append(item)
+    {
+        console.assert(item.series === undefined);
+        item.series = this;
+        item.seriesIndex = this._data.length;
+        this._data.push(item);
+    }
+
+    extendToFuture()
+    {
+        if (!this._data.length)
+            return;
+        var lastPoint = this._data[this._data.length - 1];
+        this._data.push({
+            series: this,
+            seriesIndex: this._data.length,
+            time: Date.now() + 365 * 24 * 3600 * 1000,
+            value: lastPoint.value,
+            interval: lastPoint.interval,
+        });
+    }
+
+    firstPoint() { return this._data.length ? this._data[0] : null; }
+    lastPoint() { return this._data.length ? this._data[this._data.length - 1] : null; }
+
+    previousPoint(point)
+    {
+        console.assert(point.series == this);
+        if (!point.seriesIndex)
+            return null;
+        return this._data[point.seriesIndex - 1];
+    }
+
+    nextPoint(point)
+    {
+        console.assert(point.series == this);
+        if (point.seriesIndex + 1 &gt;= this._data.length)
+            return null;
+        return this._data[point.seriesIndex + 1];
+    }
+
+    findPointByIndex(index)
+    {
+        if (!this._data || index &lt; 0 || index &gt;= this._data.length)
+            return null;
+        return this._data[index];
+    }
+
+    findById(id) { return this._data.find(function (point) { return point.id == id }); }
+
+    findPointAfterTime(time) { return this._data.find(function (point) { return point.time &gt;= time; }); }
+
+    dataBetweenPoints(firstPoint, lastPoint)
+    {
+        var data = this._data;
+        var filteredData = [];
+        for (var i = firstPoint.seriesIndex; i &lt;= lastPoint.seriesIndex; i++) {
+            if (!data[i].markedOutlier)
+                filteredData.push(data[i]);
+        }
+        return filteredData;
+    }
+
+};
</ins></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3pageschartpanestatusviewjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/pages/chart-pane-status-view.js (198461 => 198462)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/pages/chart-pane-status-view.js        2016-03-19 01:37:45 UTC (rev 198461)
+++ trunk/Websites/perf.webkit.org/public/v3/pages/chart-pane-status-view.js        2016-03-19 02:17:48 UTC (rev 198462)
</span><span class="lines">@@ -44,31 +44,33 @@
</span><span class="cx">             };
</span><span class="cx"> 
</span><span class="cx">             return element('tr', {class: selected ? 'selected' : '', onclick: action}, [
</span><del>-                element('td', info.name),
</del><ins>+                element('td', info.repository.name()),
</ins><span class="cx">                 element('td', info.url ? link(info.label, info.label, info.url, true) : info.label),
</span><span class="cx">                 element('td', {class: 'commit-viewer-opener'}, link('\u00BB', action)),
</span><span class="cx">             ]);
</span><span class="cx">         });
</span><span class="cx"> 
</span><span class="cx">         if (this._buildInfo) {
</span><del>-            var number = this._buildInfo.buildNumber();
-            var builder = Builder.findById(this._buildInfo.builderId());
-            var url = null;
-            if (builder)
-                url = builder.urlForBuild(number);
-            var buildTime = this._buildInfo.formattedBuildTime();
</del><ins>+            var build = this._buildInfo;
+            var number = build.buildNumber();
+            var buildTime = this._formatTime(build.buildTime());
+            var url = build.url();
</ins><span class="cx"> 
</span><span class="cx">             tableContent.unshift(element('tr', [
</span><span class="cx">                 element('td', 'Build'),
</span><del>-                element('td', {colspan: 2}, [
-                    url ? link(number, `Build ${number} on &quot;${builder.name()}&quot;`, url, true) : number,
-                    ` (${buildTime})`]),
</del><ins>+                element('td', {colspan: 2}, [url ? link(number, build.label(), url, true) : number, ` (${buildTime})`]),
</ins><span class="cx">             ]));
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         this.renderReplace(this.content().querySelector('.chart-pane-revisions'), tableContent);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    _formatTime(date)
+    {
+        console.assert(date instanceof Date);
+        return date.toISOString().replace('T', ' ').replace(/\.\d+Z$/, '');
+    }
+
</ins><span class="cx">     setCurrentRepository(repository)
</span><span class="cx">     {
</span><span class="cx">         this._currentRepository = repository;
</span><span class="lines">@@ -130,13 +132,9 @@
</span><span class="cx">         if (!currentPoint)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        var currentMeasurement = currentPoint.measurement();
-        if (!currentMeasurement)
-            return;
</del><ins>+        if (!this._chart.currentSelection())
+            this._buildInfo = currentPoint.build();
</ins><span class="cx"> 
</span><del>-        if (!this._chart.currentSelection() &amp;&amp; currentMeasurement)
-            this._buildInfo = currentMeasurement;
-
</del><span class="cx">         if (currentPoint &amp;&amp; previousPoint &amp;&amp; this._chart.currentSelection()) {
</span><span class="cx">             this._pointsRangeForAnalysis = {
</span><span class="cx">                 startPointId: previousPoint.id,
</span><span class="lines">@@ -145,40 +143,17 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         // FIXME: Rewrite the interface to obtain the list of revision changes.
</span><del>-        var previousMeasurement = previousPoint ? previousPoint.measurement() : null;
</del><ins>+        var currentRootSet = currentPoint.rootSet();
+        var previousRootSet = previousPoint ? previousPoint.rootSet() : null;
</ins><span class="cx"> 
</span><del>-        var revisions = currentMeasurement.formattedRevisions(previousMeasurement);
</del><ins>+        var repositoriesInCurrentRootSet = Repository.sortByNamePreferringOnesWithURL(currentRootSet.repositories());
</ins><span class="cx">         var revisionList = [];
</span><del>-        for (var repositoryId in revisions) {
-            var repository = Repository.findById(repositoryId);
-            var revision = revisions[repositoryId];
-            var url = revision.previousRevision ? repository.urlForRevisionRange(revision.previousRevision, revision.currentRevision) : '';
-            if (!url)
-                url = repository.urlForRevision(revision.currentRevision);
-
-            revisionList.push({
-                from: revision.previousRevision,
-                to: revision.currentRevision,
-                repository: repository,
-                name: repository.name(),
-                label: revision.label,
-                url: url,
-            });
</del><ins>+        for (var repository of repositoriesInCurrentRootSet) {
+            var currentCommit = currentRootSet.commitForRepository(repository);
+            var previousCommit = previousRootSet ? previousRootSet.commitForRepository(repository) : null;
+            revisionList.push(currentCommit.diff(previousCommit));
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        // Sort by repository names preferring ones with URL.
-        revisionList = revisionList.sort(function (a, b) {
-            if (!!a.url == !!b.url) {
-                if (a.name &gt; b.name)
-                    return 1;
-                else if (a.name &lt; b.name)
-                    return -1;
-                return 0;
-            } else if (b.url) // a &gt; b
-                return 1;
-            return -1;
-        });
-
</del><span class="cx">         this._revisionList = revisionList;
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3remotejs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/remote.js (198461 => 198462)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/remote.js        2016-03-19 01:37:45 UTC (rev 198461)
+++ trunk/Websites/perf.webkit.org/public/v3/remote.js        2016-03-19 02:17:48 UTC (rev 198462)
</span><span class="lines">@@ -1,5 +1,7 @@
</span><span class="cx"> 
</span><del>-function getJSON(path, data)
</del><ins>+var RemoteAPI = {};
+
+RemoteAPI.getJSON = function(path, data)
</ins><span class="cx"> {
</span><span class="cx">     console.assert(!path.startsWith('http:') &amp;&amp; !path.startsWith('https:') &amp;&amp; !path.startsWith('file:'));
</span><span class="cx"> 
</span><span class="lines">@@ -43,9 +45,9 @@
</span><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-function getJSONWithStatus(path, data)
</del><ins>+RemoteAPI.getJSONWithStatus = function(path, data)
</ins><span class="cx"> {
</span><del>-    return getJSON(path, data).then(function (content) {
</del><ins>+    return this.getJSON(path, data).then(function (content) {
</ins><span class="cx">         if (content['status'] != 'OK')
</span><span class="cx">             return Promise.reject(content['status']);
</span><span class="cx">         return content;
</span><span class="lines">@@ -62,7 +64,7 @@
</span><span class="cx">             for (var key in data)
</span><span class="cx">                 clonedData[key] = data[key];
</span><span class="cx">             clonedData['token'] = token;
</span><del>-            return getJSONWithStatus('../privileged-api/' + path, clonedData);
</del><ins>+            return RemoteAPI.getJSONWithStatus('../privileged-api/' + path, clonedData);
</ins><span class="cx">         });
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -72,7 +74,7 @@
</span><span class="cx">         if (this._token &amp;&amp; this._expiration &gt; Date.now() + maxNetworkLatency)
</span><span class="cx">             return Promise.resolve(this._token);
</span><span class="cx"> 
</span><del>-        return getJSONWithStatus('../privileged-api/generate-csrf-token', {}).then(function (result) {
</del><ins>+        return RemoteAPI.getJSONWithStatus('../privileged-api/generate-csrf-token', {}).then(function (result) {
</ins><span class="cx">             PrivilegedAPI._token = result['token'];
</span><span class="cx">             PrivilegedAPI._expiration = new Date(result['expiration']);
</span><span class="cx">             return PrivilegedAPI._token;
</span></span></pre>
</div>
</div>

</body>
</html>