<!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>[182496] 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/182496">182496</a></dd>
<dt>Author</dt> <dd>rniwa@webkit.org</dd>
<dt>Date</dt> <dd>2015-04-07 14:42:37 -0700 (Tue, 07 Apr 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Perf dashboard should have a way of marking outliers
https://bugs.webkit.org/show_bug.cgi?id=143466

Reviewed by Chris Dumez.

Added UI to mark a data point as an outlier as well as a button to toggle the visibility of outliers.
Added a new privileged API /privileged-api/update-run-status to store this boolean flag.

* init-database.sql: Added run_marked_outlier column to test_runs table.

* public/admin/tests.php:

* public/api/runs.php:
(main): Only emit Cache-Control and Expires headers in v1 UI.
(RunsGenerator::format_run): Emit markedOutlier.

* public/include/admin-header.php:

* public/include/db.php:
(Database::is_true): Made it static.

* public/include/manifest.php:
(Manifest::platforms):

* public/index.html: Call into /api/runs/ with ?cache=true.

* public/privileged-api/update-run-status.php: Added.
(main): Updates the newly added column in test_runs table.

* public/v2/app.js:
(App.Pane._fetch):
(App.Pane.refetchRuns): Extracted from App.Pane._fetch.
(App.Pane._didFetchRuns): Renamed from _updateChartData.
(App.Pane._setNewChartData): Added. Pick the right time series based based on the value of showOutlier.
Cloning chartData is necessary when toggling the outlier visibility or using statistics tools because
the interactive chart component only observes changes to chartData and not individual properties of it.
(App.Pane._highlightPointsMarkedAsOutlier): Added. Highlight points marked as outliers.
(App.Pane._movingAverageOrEnvelopeStrategyDidChange): Call to _setNewChartData replaced the code to
clone chartData here.

(App.PaneController.actions.toggleShowOutlier): Toggle the visibility of points marked as outliers by
invoking App.Pane._setNewChartData.
(App.PaneController._detailsChanged): Don't hide the analysis pane when details changed since keep
opening the pane for marking points as outliers would be annoying.
(App.PaneController._updateCanAnalyze): Update 'cannotMarkOutlier' as well as 'cannotAnalyze'.
(App.PaneController.selectedMeasurement): Added.
(App.PaneController.showOutlierTitle): Added.
(App.PaneController._selectedItemIsMarkedOutlierDidChange): Added. Call out to setMarkedOutlier to
mark the selected point as an outlier via the newly added privileged API.

* public/v2/chart-pane.css: Updated styles.

* public/v2/data.js:
(PrivilegedAPI._post): Report the semantic errors.
(Measurement.prototype.markedOutlier): Added.
(Measurement.prototype.setMarkedOutlier): Added. Uses PrivilegedAPI to update the database.
(RunsData.prototype.timeSeriesByCommitTime): Added a new argument, includeOutliers, to indicate
whether the time series should include measurements marked as outliers or not.
(RunsData.prototype.timeSeriesByBuildTime): Ditto.
(RunsData.prototype._timeSeriesByTimeInternal): Extracted from timeSeriesByCommitTime and
timeSeriesByBuildTime to share code. Now ignores measurements marked as outliers if needed.

* public/v2/index.html: Added an icon for showing and hiding outliers. Also added a checkbox to
mark individual points as outliers.

* public/v2/interactive-chart.js:
(App.InteractiveChartComponent._selectClosestPointToMouseAsCurrentItem): Re-enable the distance
heuristics that takes vertical closeness into account. This heuristics is more useful when marking
some points as outliers. This heuristics was disabled because the behavior was unpredictable but
with the arrow key navigation support, this is no longer an issue.

* public/v2/manifest.js:
(App.Manifest._formatFetchedData): Added showOutlier to the chart data. This function dynamically
updates the time series in this chart data in order to include or exclude outliers.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkWebsitesperfwebkitorgChangeLog">trunk/Websites/perf.webkit.org/ChangeLog</a></li>
<li><a href="#trunkWebsitesperfwebkitorginitdatabasesql">trunk/Websites/perf.webkit.org/init-database.sql</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicadmintestsphp">trunk/Websites/perf.webkit.org/public/admin/tests.php</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicapirunsphp">trunk/Websites/perf.webkit.org/public/api/runs.php</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicincludeadminheaderphp">trunk/Websites/perf.webkit.org/public/include/admin-header.php</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicincludedbphp">trunk/Websites/perf.webkit.org/public/include/db.php</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicincludemanifestphp">trunk/Websites/perf.webkit.org/public/include/manifest.php</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicindexhtml">trunk/Websites/perf.webkit.org/public/index.html</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv2appjs">trunk/Websites/perf.webkit.org/public/v2/app.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv2chartpanecss">trunk/Websites/perf.webkit.org/public/v2/chart-pane.css</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv2datajs">trunk/Websites/perf.webkit.org/public/v2/data.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv2indexhtml">trunk/Websites/perf.webkit.org/public/v2/index.html</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv2interactivechartjs">trunk/Websites/perf.webkit.org/public/v2/interactive-chart.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv2manifestjs">trunk/Websites/perf.webkit.org/public/v2/manifest.js</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkWebsitesperfwebkitorgpublicprivilegedapiupdaterunstatusphp">trunk/Websites/perf.webkit.org/public/privileged-api/update-run-status.php</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 (182495 => 182496)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/ChangeLog        2015-04-07 21:34:05 UTC (rev 182495)
+++ trunk/Websites/perf.webkit.org/ChangeLog        2015-04-07 21:42:37 UTC (rev 182496)
</span><span class="lines">@@ -1,3 +1,80 @@
</span><ins>+2015-04-07  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
+
+        Perf dashboard should have a way of marking outliers
+        https://bugs.webkit.org/show_bug.cgi?id=143466
+
+        Reviewed by Chris Dumez.
+
+        Added UI to mark a data point as an outlier as well as a button to toggle the visibility of outliers.
+        Added a new privileged API /privileged-api/update-run-status to store this boolean flag.
+
+        * init-database.sql: Added run_marked_outlier column to test_runs table.
+
+        * public/admin/tests.php:
+
+        * public/api/runs.php:
+        (main): Only emit Cache-Control and Expires headers in v1 UI.
+        (RunsGenerator::format_run): Emit markedOutlier.
+
+        * public/include/admin-header.php:
+
+        * public/include/db.php:
+        (Database::is_true): Made it static.
+
+        * public/include/manifest.php:
+        (Manifest::platforms):
+
+        * public/index.html: Call into /api/runs/ with ?cache=true.
+
+        * public/privileged-api/update-run-status.php: Added.
+        (main): Updates the newly added column in test_runs table.
+
+        * public/v2/app.js:
+        (App.Pane._fetch):
+        (App.Pane.refetchRuns): Extracted from App.Pane._fetch.
+        (App.Pane._didFetchRuns): Renamed from _updateChartData.
+        (App.Pane._setNewChartData): Added. Pick the right time series based based on the value of showOutlier.
+        Cloning chartData is necessary when toggling the outlier visibility or using statistics tools because
+        the interactive chart component only observes changes to chartData and not individual properties of it.
+        (App.Pane._highlightPointsMarkedAsOutlier): Added. Highlight points marked as outliers.
+        (App.Pane._movingAverageOrEnvelopeStrategyDidChange): Call to _setNewChartData replaced the code to
+        clone chartData here.
+
+        (App.PaneController.actions.toggleShowOutlier): Toggle the visibility of points marked as outliers by
+        invoking App.Pane._setNewChartData.
+        (App.PaneController._detailsChanged): Don't hide the analysis pane when details changed since keep
+        opening the pane for marking points as outliers would be annoying.
+        (App.PaneController._updateCanAnalyze): Update 'cannotMarkOutlier' as well as 'cannotAnalyze'.
+        (App.PaneController.selectedMeasurement): Added.
+        (App.PaneController.showOutlierTitle): Added.
+        (App.PaneController._selectedItemIsMarkedOutlierDidChange): Added. Call out to setMarkedOutlier to
+        mark the selected point as an outlier via the newly added privileged API.
+
+        * public/v2/chart-pane.css: Updated styles.
+
+        * public/v2/data.js:
+        (PrivilegedAPI._post): Report the semantic errors.
+        (Measurement.prototype.markedOutlier): Added.
+        (Measurement.prototype.setMarkedOutlier): Added. Uses PrivilegedAPI to update the database.
+        (RunsData.prototype.timeSeriesByCommitTime): Added a new argument, includeOutliers, to indicate
+        whether the time series should include measurements marked as outliers or not.
+        (RunsData.prototype.timeSeriesByBuildTime): Ditto.
+        (RunsData.prototype._timeSeriesByTimeInternal): Extracted from timeSeriesByCommitTime and
+        timeSeriesByBuildTime to share code. Now ignores measurements marked as outliers if needed.
+
+        * public/v2/index.html: Added an icon for showing and hiding outliers. Also added a checkbox to
+        mark individual points as outliers.
+
+        * public/v2/interactive-chart.js:
+        (App.InteractiveChartComponent._selectClosestPointToMouseAsCurrentItem): Re-enable the distance
+        heuristics that takes vertical closeness into account. This heuristics is more useful when marking
+        some points as outliers. This heuristics was disabled because the behavior was unpredictable but
+        with the arrow key navigation support, this is no longer an issue.
+
+        * public/v2/manifest.js:
+        (App.Manifest._formatFetchedData): Added showOutlier to the chart data. This function dynamically
+        updates the time series in this chart data in order to include or exclude outliers.
+
</ins><span class="cx"> 2015-04-03  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Perf dashboard should be able to trigger A/B testing jobs for iOS
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorginitdatabasesql"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/init-database.sql (182495 => 182496)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/init-database.sql        2015-04-07 21:34:05 UTC (rev 182495)
+++ trunk/Websites/perf.webkit.org/init-database.sql        2015-04-07 21:42:37 UTC (rev 182496)
</span><span class="lines">@@ -135,6 +135,7 @@
</span><span class="cx">     run_mean_cache double precision,
</span><span class="cx">     run_sum_cache double precision,
</span><span class="cx">     run_square_sum_cache double precision,
</span><ins>+    run_marked_outlier boolean,
</ins><span class="cx">     CONSTRAINT test_config_build_must_be_unique UNIQUE(run_config, run_build));
</span><span class="cx"> CREATE INDEX run_config_index ON test_runs(run_config);
</span><span class="cx"> CREATE INDEX run_build_index ON test_runs(run_build);
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicadmintestsphp"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/admin/tests.php (182495 => 182496)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/admin/tests.php        2015-04-07 21:34:05 UTC (rev 182495)
+++ trunk/Websites/perf.webkit.org/public/admin/tests.php        2015-04-07 21:42:37 UTC (rev 182496)
</span><span class="lines">@@ -196,9 +196,9 @@
</span><span class="cx">                         if (!$configurations)
</span><span class="cx">                             continue;
</span><span class="cx">                         echo &quot;&lt;label&gt;&lt;input type=\&quot;checkbox\&quot; name=\&quot;metric_platforms[]\&quot; value=\&quot;{$platform['platform_id']}\&quot;&quot;;
</span><del>-                        if ($db-&gt;is_true($configurations[0]['config_is_in_dashboard']))
</del><ins>+                        if (Database::is_true($configurations[0]['config_is_in_dashboard']))
</ins><span class="cx">                             echo ' checked';
</span><del>-                        else if ($db-&gt;is_true($platform['platform_hidden']))
</del><ins>+                        else if (Database::is_true($platform['platform_hidden']))
</ins><span class="cx">                             echo 'disabled';
</span><span class="cx">                         echo &quot;&gt;$platform_name&lt;/label&gt;&quot;;
</span><span class="cx">                     }
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicapirunsphp"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/api/runs.php (182495 => 182496)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/api/runs.php        2015-04-07 21:34:05 UTC (rev 182495)
+++ trunk/Websites/perf.webkit.org/public/api/runs.php        2015-04-07 21:42:37 UTC (rev 182496)
</span><span class="lines">@@ -43,10 +43,10 @@
</span><span class="cx">         exit_with_error('ConfigurationNotFound');
</span><span class="cx"> 
</span><span class="cx">     $test_group_id = array_get($_GET, 'testGroup');
</span><ins>+    $should_cache = array_get($_GET, 'cache');
</ins><span class="cx">     if ($test_group_id)
</span><span class="cx">         $test_group_id = intval($test_group_id);
</span><del>-    else {
-        // FIXME: We should support revalication as well as caching results in the server side.
</del><ins>+    else if ($should_cache) { // Only v1 UI needs caching.
</ins><span class="cx">         $maxage = config('jsonCacheMaxAge');
</span><span class="cx">         header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $maxage) . ' GMT');
</span><span class="cx">         header(&quot;Cache-Control: maxage=$maxage&quot;);
</span><span class="lines">@@ -102,6 +102,7 @@
</span><span class="cx">             'iterationCount' =&gt; intval($run['run_iteration_count_cache']),
</span><span class="cx">             'sum' =&gt; floatval($run['run_sum_cache']),
</span><span class="cx">             'squareSum' =&gt; floatval($run['run_square_sum_cache']),
</span><ins>+            'markedOutlier' =&gt; Database::is_true($run['run_marked_outlier']),
</ins><span class="cx">             'revisions' =&gt; self::parse_revisions_array($run['revisions']),
</span><span class="cx">             'build' =&gt; $run['build_id'],
</span><span class="cx">             'buildTime' =&gt; Database::to_js_time($run['build_time']),
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicincludeadminheaderphp"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/include/admin-header.php (182495 => 182496)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/include/admin-header.php        2015-04-07 21:34:05 UTC (rev 182495)
+++ trunk/Websites/perf.webkit.org/public/include/admin-header.php        2015-04-07 21:42:37 UTC (rev 182496)
</span><span class="lines">@@ -130,7 +130,7 @@
</span><span class="cx">             $show_update_button = $show_update_button_if_needed;
</span><span class="cx">             break;
</span><span class="cx">         case 'boolean':
</span><del>-            $checkedness = $this-&gt;db-&gt;is_true($value) ? ' checked' : '';
</del><ins>+            $checkedness = Database::is_true($value) ? ' checked' : '';
</ins><span class="cx">             echo &lt;&lt;&lt; END
</span><span class="cx"> &lt;input type=&quot;checkbox&quot; name=&quot;$name&quot;$checkedness&gt;
</span><span class="cx"> END;
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicincludedbphp"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/include/db.php (182495 => 182496)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/include/db.php        2015-04-07 21:34:05 UTC (rev 182495)
+++ trunk/Websites/perf.webkit.org/public/include/db.php        2015-04-07 21:42:37 UTC (rev 182496)
</span><span class="lines">@@ -60,7 +60,7 @@
</span><span class="cx">         $this-&gt;connection = false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    function is_true($value) {
</del><ins>+    static function is_true($value) {
</ins><span class="cx">         return $value == 't';
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicincludemanifestphp"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/include/manifest.php (182495 => 182496)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/include/manifest.php        2015-04-07 21:34:05 UTC (rev 182495)
+++ trunk/Websites/perf.webkit.org/public/include/manifest.php        2015-04-07 21:42:37 UTC (rev 182496)
</span><span class="lines">@@ -79,7 +79,7 @@
</span><span class="cx">         $platform_metrics = array();
</span><span class="cx">         if ($config_table) {
</span><span class="cx">             foreach ($config_table as $config_row) {
</span><del>-                if ($is_dashboard &amp;&amp; !$this-&gt;db-&gt;is_true($config_row['config_is_in_dashboard']))
</del><ins>+                if ($is_dashboard &amp;&amp; !Database::is_true($config_row['config_is_in_dashboard']))
</ins><span class="cx">                     continue;
</span><span class="cx"> 
</span><span class="cx">                 $new_last_modified = array_get($config_row, 'config_runs_last_modified', 0);
</span><span class="lines">@@ -104,7 +104,7 @@
</span><span class="cx">         $platforms = array();
</span><span class="cx">         if ($platform_table) {
</span><span class="cx">             foreach ($platform_table as $platform_row) {
</span><del>-                if ($this-&gt;db-&gt;is_true($platform_row['platform_hidden']))
</del><ins>+                if (Database::is_true($platform_row['platform_hidden']))
</ins><span class="cx">                     continue;
</span><span class="cx">                 $id = $platform_row['platform_id'];
</span><span class="cx">                 if (array_key_exists($id, $platform_metrics)) {
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicindexhtml"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/index.html (182495 => 182496)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/index.html        2015-04-07 21:34:05 UTC (rev 182495)
+++ trunk/Websites/perf.webkit.org/public/index.html        2015-04-07 21:42:37 UTC (rev 182496)
</span><span class="lines">@@ -840,7 +840,7 @@
</span><span class="cx">         return runs;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    $.getJSON('api/runs/' + filename, function (response) {
</del><ins>+    $.getJSON('api/runs/' + filename + '?cache=true', function (response) {
</ins><span class="cx">         var data = response.configurations;
</span><span class="cx">         callback(createRunAndResults(data.current), createRunAndResults(data.baseline), createRunAndResults(data.target));
</span><span class="cx">     });
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicprivilegedapiupdaterunstatusphp"></a>
<div class="addfile"><h4>Added: trunk/Websites/perf.webkit.org/public/privileged-api/update-run-status.php (0 => 182496)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/privileged-api/update-run-status.php                                (rev 0)
+++ trunk/Websites/perf.webkit.org/public/privileged-api/update-run-status.php        2015-04-07 21:42:37 UTC (rev 182496)
</span><span class="lines">@@ -0,0 +1,30 @@
</span><ins>+&lt;?php
+
+require_once('../include/json-header.php');
+
+function main() {
+    $data = ensure_privileged_api_data_and_token();
+
+    $run_id = array_get($data, 'run');
+    if (!$run_id)
+        exit_with_error('MissingRunId');
+
+    $db = connect();
+    $run = $db-&gt;select_first_row('test_runs', 'run', array('id' =&gt; $run_id));
+    if (!$run)
+        exit_with_error('InvalidRun', array('run' =&gt; $run_id));
+
+    $marked_outlier = array_get($data, 'markedOutlier');
+
+    $db-&gt;begin_transaction();
+    $db-&gt;update_row('test_runs', 'run', array('id' =&gt; $run_id), array(
+        'id' =&gt; $run_id,
+        'marked_outlier' =&gt; $marked_outlier ? 't' : 'f'));
+    $db-&gt;commit_transaction();
+
+    exit_with_success();
+}
+
+main();
+
+?&gt;
</ins></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv2appjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v2/app.js (182495 => 182496)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v2/app.js        2015-04-07 21:34:05 UTC (rev 182495)
+++ trunk/Websites/perf.webkit.org/public/v2/app.js        2015-04-07 21:42:37 UTC (rev 182496)
</span><span class="lines">@@ -349,29 +349,57 @@
</span><span class="cx">         else if (!this._isValidId(metricId))
</span><span class="cx">             this.set('failure', metricId ? 'Invalid metric id:' + metricId : 'Metric id was not specified');
</span><span class="cx">         else {
</span><del>-            var store = this.get('store');
-            var updateChartData = this._updateChartData.bind(this);
-            var handleErrors = this._handleFetchErrors.bind(this, platformId, metricId);
</del><ins>+            var self = this;
</ins><span class="cx">             var useCache = true;
</span><del>-            App.Manifest.fetchRunsWithPlatformAndMetric(store, platformId, metricId, null, useCache).then(function (result) {
-                    updateChartData(result);
-                    if (!result.shouldRefetch)
-                        return;
-
-                    useCache = false;
-                    App.Manifest.fetchRunsWithPlatformAndMetric(store, platformId, metricId, null, useCache)
-                        .then(updateChartData, handleErrors);
-                }, handleErrors);
</del><ins>+            App.Manifest.fetchRunsWithPlatformAndMetric(this.get('store'), platformId, metricId, null, useCache)
+                .then(function (result) {
+                    self._didFetchRuns(result);
+                    if (result.shouldRefetch)
+                        self.refetchRuns();
+                }, this._handleFetchErrors.bind(this, platformId, metricId));
</ins><span class="cx">             this.fetchAnalyticRanges();
</span><span class="cx">         }
</span><span class="cx">     }.observes('platformId', 'metricId').on('init'),
</span><del>-    _updateChartData: function (result)
</del><ins>+    refetchRuns: function () {
+        var platform = this.get('platform');
+        var metric = this.get('metric');
+        Ember.assert('refetchRuns should be called only after platform and metric are resolved', platform &amp;&amp; metric);
+
+        var useCache = false;
+        App.Manifest.fetchRunsWithPlatformAndMetric(this.get('store'), platform.get('id'), metric.get('id'), null, useCache)
+            .then(this._didFetchRuns.bind(this), this._handleFetchErrors.bind(this, platform.get('id'), metric.get('id')));
+    },
+    _didFetchRuns: function (result)
</ins><span class="cx">     {
</span><span class="cx">         this.set('platform', result.platform);
</span><span class="cx">         this.set('metric', result.metric);
</span><del>-        this.set('chartData', result.data);
</del><ins>+        this._setNewChartData(result.data);
+    },
+    _setNewChartData: function (chartData)
+    {
+        var newChartData = {};
+        for (var property in chartData)
+            newChartData[property] = chartData[property];
+
+        var showOutlier = this.get('showOutlier');
+        newChartData.showOutlier(showOutlier);
+        this.set('chartData', newChartData);
</ins><span class="cx">         this._updateMovingAverageAndEnvelope();
</span><ins>+
+        if (!this.get('anomalyDetectionStrategies').filterBy('enabled').length)
+            this._highlightPointsMarkedAsOutlier(newChartData);
</ins><span class="cx">     },
</span><ins>+    _highlightPointsMarkedAsOutlier: function (newChartData)
+    {
+        var data = newChartData.current.series();
+        var items = {};
+        for (var i = 0; i &lt; data.length; i++) {
+            if (data[i].measurement.markedOutlier())
+                items[data[i].measurement.id()] = true;
+        }
+
+        this.set('highlightedItems', items);
+    },
</ins><span class="cx">     _handleFetchErrors: function (platformId, metricId, result)
</span><span class="cx">     {
</span><span class="cx">         if (!result || typeof(result) === &quot;string&quot;)
</span><span class="lines">@@ -518,16 +546,10 @@
</span><span class="cx">         this.set('highlightedItems', anomalies);
</span><span class="cx">     },
</span><span class="cx">     _movingAverageOrEnvelopeStrategyDidChange: function () {
</span><del>-        this._updateMovingAverageAndEnvelope();
-
-        var newChartData = {};
</del><span class="cx">         var chartData = this.get('chartData');
</span><span class="cx">         if (!chartData)
</span><span class="cx">             return;
</span><del>-        for (var property in chartData)
-            newChartData[property] = chartData[property];
-        this.set('chartData', newChartData);
-
</del><ins>+        this._setNewChartData(chartData);
</ins><span class="cx">     }.observes('chosenMovingAverageStrategy', 'chosenMovingAverageStrategy.parameterList.@each.value',
</span><span class="cx">         'chosenEnvelopingStrategy', 'chosenEnvelopingStrategy.parameterList.@each.value',
</span><span class="cx">         'anomalyDetectionStrategies.@each.enabled'),
</span><span class="lines">@@ -925,6 +947,15 @@
</span><span class="cx">                 this.set('showingStatPane', false);
</span><span class="cx">             }
</span><span class="cx">         },
</span><ins>+        toggleShowOutlier: function ()
+        {
+            var pane = this.get('model');
+            pane.toggleProperty('showOutlier');
+            var chartData = pane.get('chartData');
+            if (!chartData)
+                return;
+            pane._setNewChartData(chartData);
+        },
</ins><span class="cx">         createAnalysisTask: function ()
</span><span class="cx">         {
</span><span class="cx">             var name = this.get('newAnalysisTaskName');
</span><span class="lines">@@ -978,10 +1009,6 @@
</span><span class="cx">             Ember.run.debounce(this, 'propagateZoom', 100);
</span><span class="cx">         },
</span><span class="cx">     },
</span><del>-    _detailsChanged: function ()
-    {
-        this.set('showingAnalysisPane', false);
-    }.observes('details'),
</del><span class="cx">     _overviewSelectionChanged: function ()
</span><span class="cx">     {
</span><span class="cx">         var overviewSelection = this.get('overviewSelection');
</span><span class="lines">@@ -1013,9 +1040,43 @@
</span><span class="cx">     }.observes('parentController.sharedZoom').on('init'),
</span><span class="cx">     _updateCanAnalyze: function ()
</span><span class="cx">     {
</span><del>-        var points = this.get('model').get('selectedPoints');
</del><ins>+        var pane = this.get('model');
+        var points = pane.get('selectedPoints');
</ins><span class="cx">         this.set('cannotAnalyze', !this.get('newAnalysisTaskName') || !points || points.length &lt; 2);
</span><del>-    }.observes('newAnalysisTaskName', 'model.selectedPoints'),
</del><ins>+        this.set('cannotMarkOutlier', !!points || !this.get('selectedItem'));
+
+        var selectedMeasurement = this.selectedMeasurement();
+        this.set('selectedItemIsMarkedOutlier', selectedMeasurement &amp;&amp; selectedMeasurement.markedOutlier());
+
+    }.observes('newAnalysisTaskName', 'model.selectedPoints', 'model.selectedItem').on('init'),
+    selectedMeasurement: function () {
+        var chartData = this.get('model').get('chartData');
+        var selectedItem = this.get('selectedItem');
+        if (!chartData || !selectedItem)
+            return null;
+        var point = chartData.current.findPointByMeasurementId(selectedItem);
+        Ember.assert('selectedItem should always be in the current chart data', point);
+        return point.measurement;
+    },
+    showOutlierTitle: function ()
+    {
+        return this.get('showOutlier') ? 'Hide outliers' : 'Show outliers';
+    }.property('showOutlier'),
+    _selectedItemIsMarkedOutlierDidChange: function ()
+    {
+        var selectedMeasurement = this.selectedMeasurement();
+        if (!selectedMeasurement)
+            return;
+        var selectedItemIsMarkedOutlier = this.get('selectedItemIsMarkedOutlier');
+        if (selectedMeasurement.markedOutlier() == selectedItemIsMarkedOutlier)
+            return;
+        var pane = this.get('model');
+        selectedMeasurement.setMarkedOutlier(!!selectedItemIsMarkedOutlier).then(function () {
+            pane.refetchRuns();
+        }, function (error) {
+            alert(error);
+        });
+    }.observes('selectedItemIsMarkedOutlier'),
</ins><span class="cx"> });
</span><span class="cx"> 
</span><span class="cx"> App.AnalysisRoute = Ember.Route.extend({
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv2chartpanecss"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v2/chart-pane.css (182495 => 182496)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v2/chart-pane.css        2015-04-07 21:34:05 UTC (rev 182495)
+++ trunk/Websites/perf.webkit.org/public/v2/chart-pane.css        2015-04-07 21:42:37 UTC (rev 182496)
</span><span class="lines">@@ -44,13 +44,30 @@
</span><span class="cx"> .chart-pane a.stat-button {
</span><span class="cx">     display: inline-block;
</span><span class="cx">     position: absolute;
</span><del>-    right: 3.15rem;
</del><ins>+    right: 4.45rem;
</ins><span class="cx">     top: 0.55rem;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-.chart-pane a.bugs-button {
</del><ins>+.chart-pane a.outlier-button {
</ins><span class="cx">     display: inline-block;
</span><span class="cx">     position: absolute;
</span><ins>+    right: 3.25rem; /* Shifted to left by 0.1rem for better aesthetics */
+    top: 0.55rem;
+}
+
+a.outlier-button.hide g.show-outlier-icon {
+    fill: transparent;
+    stroke: transparent;
+}
+
+a.outlier-button.show g.hide-outlier-icon {
+    fill: transparent;
+    stroke: transparent;
+}
+
+.chart-pane a.analysis-button {
+    display: inline-block;
+    position: absolute;
</ins><span class="cx">     right: 1.85rem;
</span><span class="cx">     top: 0.55rem;
</span><span class="cx"> }
</span><span class="lines">@@ -78,26 +95,25 @@
</span><span class="cx">     display: none;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-.stat-pane {
</del><ins>+.stat-pane,
+.annotation-pane {
</ins><span class="cx">     right: 2.6rem;
</span><span class="cx">     padding: 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-.stat-pane fieldset {
-    border: solid 1px #ccc;
-    border-radius: 0.5rem;
-    margin: 0.2rem;
-    padding: 0;
</del><ins>+.popup-pane &gt; .caution {
+    margin: 0;
+    padding: 0.3rem 0.5rem;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-.stat-option {
</del><ins>+.popup-pane &gt; section {
</ins><span class="cx">     margin: 0;
</span><span class="cx">     padding: 0;
</span><span class="cx">     font-size: 0.8rem;
</span><span class="cx">     max-width: 17rem;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-.stat-option h1 {
</del><ins>+.popup-pane &gt; section &gt; h1 {
</ins><span class="cx">     font-size: inherit;
</span><span class="cx">     line-height: 0.8rem;
</span><span class="cx">     padding: 0.3rem 0.5rem;
</span><span class="lines">@@ -106,11 +122,11 @@
</span><span class="cx">     border-bottom: solid 1px #ccc;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-.stat-option:first-child h1 {
</del><ins>+.popup-pane &gt; section:first-child h1 {
</ins><span class="cx">     border-top: none;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-.stat-option &gt; * {
</del><ins>+.popup-pane &gt; section &gt; * {
</ins><span class="cx">     display: block;
</span><span class="cx">     margin: 0.1rem 0.5rem 0.1rem 1rem;
</span><span class="cx"> }
</span><span class="lines">@@ -119,14 +135,10 @@
</span><span class="cx">     width: 4rem;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-.analysis-pane {
</del><ins>+.annotation-pane {
</ins><span class="cx">     right: 1.3rem;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-.analysis-pane &gt; * {
-    margin: 0.2rem;
-}
-
</del><span class="cx"> .search-pane {
</span><span class="cx">     right: 0rem;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv2datajs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v2/data.js (182495 => 182496)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v2/data.js        2015-04-07 21:34:05 UTC (rev 182495)
+++ trunk/Websites/perf.webkit.org/public/v2/data.js        2015-04-07 21:42:37 UTC (rev 182496)
</span><span class="lines">@@ -39,9 +39,10 @@
</span><span class="cx">             data: parameters ? JSON.stringify(parameters) : '{}',
</span><span class="cx">             dataType: 'json',
</span><span class="cx">         }).done(function (data) {
</span><del>-            if (data.status != 'OK')
</del><ins>+            if (data.status != 'OK') {
+                console.log('PrivilegedAPI failed', data);
</ins><span class="cx">                 reject(data.status);
</span><del>-            else
</del><ins>+            } else
</ins><span class="cx">                 resolve(data);
</span><span class="cx">         }).fail(function (xhr, status, error) {
</span><span class="cx">             reject(xhr.status + (error ? ', ' + error : '') + '\n\nWith response:\n' + xhr.responseText);
</span><span class="lines">@@ -288,6 +289,20 @@
</span><span class="cx">     return bugs &amp;&amp; Object.keys(bugs).length;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+Measurement.prototype.markedOutlier = function ()
+{
+    return this._raw['markedOutlier'];
+}
+
+Measurement.prototype.setMarkedOutlier = function (markedOutlier)
+{
+    var params = {'run': this.id(), 'markedOutlier': markedOutlier};
+    return PrivilegedAPI.sendRequest('update-run-status', params).then(function (data) {
+    }, function (error) {
+        alert('Failed to update the outlier status: ' + error);
+    });
+}
+
</ins><span class="cx"> function RunsData(rawData)
</span><span class="cx"> {
</span><span class="cx">     this._measurements = rawData.map(function (run) { return new Measurement(run); });
</span><span class="lines">@@ -298,29 +313,32 @@
</span><span class="cx">     return this._measurements.length;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-RunsData.prototype.timeSeriesByCommitTime = function ()
</del><ins>+RunsData.prototype.timeSeriesByCommitTime = function (includeOutliers)
</ins><span class="cx"> {
</span><del>-    return new TimeSeries(this._measurements.map(function (measurement) {
-        var confidenceInterval = measurement.confidenceInterval();
-        return {
-            measurement: measurement,
-            time: measurement.latestCommitTime(),
-            value: measurement.mean(),
-            interval: measurement.confidenceInterval(),
-        };
-    }));
</del><ins>+    return this._timeSeriesByTimeInternal(true, includeOutliers);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-RunsData.prototype.timeSeriesByBuildTime = function ()
</del><ins>+RunsData.prototype.timeSeriesByBuildTime = function (includeOutliers)
</ins><span class="cx"> {
</span><del>-    return new TimeSeries(this._measurements.map(function (measurement) {
-        return {
</del><ins>+    return this._timeSeriesByTimeInternal(false, includeOutliers);
+}
+
+RunsData.prototype._timeSeriesByTimeInternal = function (useCommitType, includeOutliers)
+{
+    var series = new Array();
+    var seriesIndex = 0;
+    for (var measurement of this._measurements) {
+        if (measurement.markedOutlier() &amp;&amp; !includeOutliers)
+            continue;
+        series.push({
</ins><span class="cx">             measurement: measurement,
</span><del>-            time: measurement.buildTime(),
</del><ins>+            time: useCommitType ? measurement.latestCommitTime() : measurement.buildTime(),
</ins><span class="cx">             value: measurement.mean(),
</span><span class="cx">             interval: measurement.confidenceInterval(),
</span><del>-        };
-    }));
</del><ins>+            markedOutlier: measurement.markedOutlier(),
+        });
+    }
+    return new TimeSeries(series);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // FIXME: We need to devise a way to fetch runs in multiple chunks so that
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv2indexhtml"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v2/index.html (182495 => 182496)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v2/index.html        2015-04-07 21:34:05 UTC (rev 182495)
+++ trunk/Websites/perf.webkit.org/public/v2/index.html        2015-04-07 21:42:37 UTC (rev 182496)
</span><span class="lines">@@ -150,13 +150,15 @@
</span><span class="cx">                     {{#if movingAverageStrategies}}
</span><span class="cx">                         &lt;a href=&quot;javascript:false&quot; title=&quot;Statistical Tools&quot; class=&quot;stat-button&quot; {{action &quot;toggleStatPane&quot;}}&gt;{{partial &quot;stat-button&quot;}}&lt;/a&gt;
</span><span class="cx">                     {{/if}}
</span><del>-                    {{#if App.Manifest.bugTrackers}}
-                        &lt;a href=&quot;javascript:false&quot; title=&quot;Analysis&quot; class=&quot;bugs-button&quot; {{action &quot;toggleBugsPane&quot;}}&gt;
-                            {{partial &quot;analysis-button&quot;}}
-                        &lt;/a&gt;
-                    {{/if}}
</del><ins>+                    &lt;a href=&quot;javascript:false&quot; {{bind-attr title=showOutlierTitle class=&quot;:outlier-button showOutlier:show:hide&quot;}}
+                        {{action &quot;toggleShowOutlier&quot;}}&gt;
+                        {{partial &quot;outlier-button&quot;}}
+                    &lt;/a&gt;
+                    &lt;a href=&quot;javascript:false&quot; title=&quot;Analyze the selected range&quot; class=&quot;analysis-button&quot; {{action &quot;toggleBugsPane&quot;}}&gt;
+                        {{partial &quot;analysis-button&quot;}}
+                    &lt;/a&gt;
</ins><span class="cx">                     {{#if App.Manifest.repositoriesWithReportedCommits}}
</span><del>-                        &lt;a href=&quot;javascript:false&quot; title=&quot;Search&quot; class=&quot;search-button&quot; {{action &quot;toggleSearchPane&quot;}}&gt;{{partial &quot;search-button&quot;}}&lt;/a&gt;
</del><ins>+                        &lt;a href=&quot;javascript:false&quot; title=&quot;Search commits by a keyword&quot; class=&quot;search-button&quot; {{action &quot;toggleSearchPane&quot;}}&gt;{{partial &quot;search-button&quot;}}&lt;/a&gt;
</ins><span class="cx">                     {{/if}}
</span><span class="cx">                 &lt;/header&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -204,8 +206,14 @@
</span><span class="cx">                 &lt;/div&gt;
</span><span class="cx"> 
</span><span class="cx">                 &lt;div {{bind-attr class=&quot;:popup-pane :analysis-pane showingAnalysisPane::hidden&quot;}}&gt;
</span><del>-                    &lt;label&gt;Name: {{input type=text value=newAnalysisTaskName}}&lt;/label&gt;
-                    &lt;button {{action &quot;createAnalysisTask&quot;}} {{bind-attr disabled=cannotAnalyze}}&gt;Analyze&lt;/button&gt;
</del><ins>+                    &lt;section class=&quot;analysis-option-option&quot;&gt;
+                        &lt;h1&gt;Start A/B testing or associate bugs&lt;/h1&gt;
+                        &lt;label&gt;Name: {{input type=text value=newAnalysisTaskName}} &lt;button {{action &quot;createAnalysisTask&quot;}} {{bind-attr disabled=cannotAnalyze}}&gt;Analyze&lt;/button&gt;&lt;/label&gt;
+                    &lt;/section&gt;
+                    &lt;section class=&quot;analysis-option-option&quot;&gt;
+                        &lt;h1&gt;Marking outliers&lt;/h1&gt;
+                        &lt;label&gt;{{input type=checkbox checked=selectedItemIsMarkedOutlier disabled=cannotMarkOutlier}} Mark as an outlier and hide it.&lt;/label&gt;
+                    &lt;/section&gt;
</ins><span class="cx">                 &lt;/div&gt;
</span><span class="cx"> 
</span><span class="cx">                 &lt;form {{bind-attr class=&quot;:popup-pane :search-pane showingSearchPane::hidden&quot;}}&gt;
</span><span class="lines">@@ -404,6 +412,26 @@
</span><span class="cx">         &lt;/section&gt;
</span><span class="cx">     &lt;/script&gt;
</span><span class="cx"> 
</span><ins>+    &lt;script type=&quot;text/x-handlebars&quot; data-template-name=&quot;outlier-button&quot;&gt;
+        &lt;svg class=&quot;outlier-button icon-button&quot; viewBox=&quot;0 0 100 100&quot;&gt;
+            &lt;g stroke=&quot;black&quot; fill=&quot;black&quot; stroke-width=&quot;15&quot;&gt;
+                &lt;line x1=&quot;0&quot; y1=&quot;70&quot; x2=&quot;40&quot; y2=&quot;70&quot;/&gt;
+                &lt;circle cx=&quot;15&quot; cy=&quot;70&quot; r=&quot;8&quot;/&gt;
+                &lt;circle cx=&quot;45&quot; cy=&quot;70&quot; r=&quot;8&quot;/&gt;
+                &lt;circle cx=&quot;85&quot; cy=&quot;70&quot; r=&quot;8&quot;/&gt;
+                &lt;line x1=&quot;85&quot; y1=&quot;70&quot; x2=&quot;100&quot; y2=&quot;70&quot;/&gt;
+                &lt;g class=&quot;show-outlier-icon&quot;&gt;
+                    &lt;line x1=&quot;45&quot; y1=&quot;70&quot; x2=&quot;65&quot; y2=&quot;20&quot;/&gt;
+                    &lt;line x1=&quot;65&quot; y1=&quot;20&quot; x2=&quot;85&quot; y2=&quot;70&quot;/&gt;
+                    &lt;circle cx=&quot;65&quot; cy=&quot;20&quot; r=&quot;8&quot;/&gt;
+                &lt;/g&gt;
+                &lt;g class=&quot;hide-outlier-icon&quot;&gt;
+                    &lt;line x1=&quot;45&quot; y1=&quot;70&quot; x2=&quot;85&quot; y2=&quot;70&quot;/&gt;
+                &lt;/g&gt;
+            &lt;/g&gt;
+        &lt;/svg&gt;
+    &lt;/script&gt;
+
</ins><span class="cx">     &lt;script type=&quot;text/x-handlebars&quot; data-template-name=&quot;analysis-button&quot;&gt;
</span><span class="cx">         &lt;svg class=&quot;analysis-button icon-button&quot; viewBox=&quot;0 0 100 100&quot;&gt;
</span><span class="cx">             &lt;g stroke=&quot;black&quot; fill=&quot;black&quot; stroke-width=&quot;15&quot;&gt;
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv2interactivechartjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v2/interactive-chart.js (182495 => 182496)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v2/interactive-chart.js        2015-04-07 21:34:05 UTC (rev 182495)
+++ trunk/Websites/perf.webkit.org/public/v2/interactive-chart.js        2015-04-07 21:42:37 UTC (rev 182496)
</span><span class="lines">@@ -524,9 +524,6 @@
</span><span class="cx">             var yDiff = mY - point.y;
</span><span class="cx">             return xDiff * xDiff + yDiff * yDiff / 16; // Favor horizontal affinity.
</span><span class="cx">         };
</span><del>-        distanceHeuristics = function (m) {
-            return Math.abs(xScale(m.time) - point.x);
-        }
</del><span class="cx"> 
</span><span class="cx">         var newItemIndex;
</span><span class="cx">         if (point &amp;&amp; !this._currentSelection()) {
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv2manifestjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v2/manifest.js (182495 => 182496)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v2/manifest.js        2015-04-07 21:34:05 UTC (rev 182495)
+++ trunk/Websites/perf.webkit.org/public/v2/manifest.js        2015-04-07 21:42:37 UTC (rev 182496)
</span><span class="lines">@@ -333,10 +333,15 @@
</span><span class="cx">         var unitSuffix = unit ? ' ' + unit : '';
</span><span class="cx">         var deltaFormatterWithoutSign = useSI ? d3.format('.2s') : d3.format('.2g');
</span><span class="cx"> 
</span><ins>+        var currentTimeSeries = configurations.current.timeSeriesByCommitTime(false);
+        var baselineTimeSeries = configurations.baseline ? configurations.baseline.timeSeriesByCommitTime(false) : null;
+        var targetTimeSeries = configurations.target ? configurations.target.timeSeriesByCommitTime(false) : null;
+        var unfilteredCurrentTimeSeries, unfilteredBaselineTimeSeries, unfilteredTargetTimeSeries;
+
</ins><span class="cx">         return {
</span><del>-            current: configurations.current.timeSeriesByCommitTime(),
-            baseline: configurations.baseline ? configurations.baseline.timeSeriesByCommitTime() : null,
-            target: configurations.target ? configurations.target.timeSeriesByCommitTime() : null,
</del><ins>+            current: currentTimeSeries,
+            baseline: baselineTimeSeries,
+            target: targetTimeSeries,
</ins><span class="cx">             unit: unit,
</span><span class="cx">             formatWithUnit: function (value) { return this.formatter(value) + unitSuffix; },
</span><span class="cx">             formatWithDeltaAndUnit: function (value, delta)
</span><span class="lines">@@ -346,6 +351,17 @@
</span><span class="cx">             formatter: useSI ? d3.format('.4s') : d3.format('.4g'),
</span><span class="cx">             deltaFormatter: useSI ? d3.format('+.2s') : d3.format('+.2g'),
</span><span class="cx">             smallerIsBetter: smallerIsBetter,
</span><ins>+            showOutlier: function (show)
+            {
+                if (!unfilteredCurrentTimeSeries) {
+                    unfilteredCurrentTimeSeries = configurations.current.timeSeriesByCommitTime(true);
+                    unfilteredBaselineTimeSeries = configurations.baseline ? configurations.baseline.timeSeriesByCommitTime(true) : null;
+                    unfilteredTargetTimeSeries = configurations.target ? configurations.target.timeSeriesByCommitTime(true) : null;
+                }
+                this.current = show ? unfilteredCurrentTimeSeries : currentTimeSeries;
+                this.baseline = show ? unfilteredBaselineTimeSeries : baselineTimeSeries;
+                this.target = show ? unfilteredTargetTimeSeries : targetTimeSeries;
+            },
</ins><span class="cx">         };
</span><span class="cx">     }
</span><span class="cx"> }).create();
</span></span></pre>
</div>
</div>

</body>
</html>