<!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>[196228] trunk/PerformanceTests</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/196228">196228</a></dd>
<dt>Author</dt> <dd>jonlee@apple.com</dd>
<dt>Date</dt> <dd>2016-02-06 16:27:12 -0800 (Sat, 06 Feb 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Add a convenience function for creating a class.

The pattern for creating a class is common enough to add as a Utilities
helper function. It also makes it easy to collapse class definitions when
editing.

* Animometer/resources/debug-runner/animometer.js: Move ProgressBar definition,
since it is only used here.
* Animometer/resources/runner/animometer.js: Move ResultsDashboard and
ResultsTable definition, since it is only used here.
* Animometer/resources/extensions.js: Move Utilities definition to the top. Convert
Point, Insets, SimplePromise.
(ProgressBar): Moved to animometer.js.
(ResultsDashboard): Moved to animometer.js.
(ResultsTable): Moved to animometer.js.
* Animometer/resources/runner/benchmark-runner.js: Convert BenchmarkRunnerState,
BenchmarkRunner.
* Animometer/tests/resources/main.js: Convert Rotater, Stage, Animator, Benchmark.
* Animometer/tests/resources/sampler.js: Convert Experiment, Sampler.

Convert test primitives.
* Animometer/tests/master/resources/canvas-tests.js: Convert CanvasLineSegment,
CanvasArc, CanvasLinePoint.
* Animometer/tests/simple/resources/simple-canvas-paths.js: Convert CanvasLineSegment,
CanvasLinePoint, CanvasQuadraticSegment, CanvasQuadraticPoint, CanvasBezierSegment,
CanvasBezierPoint, CanvasArcToSegment, CanvasArcToSegmentFill, CanvasArcSegment,
CanvasArcSegmentFill, CanvasRect, CanvasRectFill.
* Animometer/tests/simple/resources/tiled-canvas-image.js: Convert CanvasImageTile.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkPerformanceTestsAnimometerresourcesdebugrunneranimometerjs">trunk/PerformanceTests/Animometer/resources/debug-runner/animometer.js</a></li>
<li><a href="#trunkPerformanceTestsAnimometerresourcesextensionsjs">trunk/PerformanceTests/Animometer/resources/extensions.js</a></li>
<li><a href="#trunkPerformanceTestsAnimometerresourcesrunneranimometerjs">trunk/PerformanceTests/Animometer/resources/runner/animometer.js</a></li>
<li><a href="#trunkPerformanceTestsAnimometerresourcesrunnerbenchmarkrunnerjs">trunk/PerformanceTests/Animometer/resources/runner/benchmark-runner.js</a></li>
<li><a href="#trunkPerformanceTestsAnimometertestsmasterresourcescanvastestsjs">trunk/PerformanceTests/Animometer/tests/master/resources/canvas-tests.js</a></li>
<li><a href="#trunkPerformanceTestsAnimometertestsresourcesmainjs">trunk/PerformanceTests/Animometer/tests/resources/main.js</a></li>
<li><a href="#trunkPerformanceTestsAnimometertestsresourcessamplerjs">trunk/PerformanceTests/Animometer/tests/resources/sampler.js</a></li>
<li><a href="#trunkPerformanceTestsAnimometertestssimpleresourcessimplecanvaspathsjs">trunk/PerformanceTests/Animometer/tests/simple/resources/simple-canvas-paths.js</a></li>
<li><a href="#trunkPerformanceTestsAnimometertestssimpleresourcestiledcanvasimagejs">trunk/PerformanceTests/Animometer/tests/simple/resources/tiled-canvas-image.js</a></li>
<li><a href="#trunkPerformanceTestsChangeLog">trunk/PerformanceTests/ChangeLog</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkPerformanceTestsAnimometerresourcesdebugrunneranimometerjs"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/Animometer/resources/debug-runner/animometer.js (196227 => 196228)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/Animometer/resources/debug-runner/animometer.js        2016-02-07 00:18:40 UTC (rev 196227)
+++ trunk/PerformanceTests/Animometer/resources/debug-runner/animometer.js        2016-02-07 00:27:12 UTC (rev 196228)
</span><span class="lines">@@ -1,3 +1,24 @@
</span><ins>+ProgressBar = Utilities.createClass(
+    function(element, ranges)
+    {
+        this._element = element;
+        this._ranges = ranges;
+        this._currentRange = 0;
+        this._updateElement();
+    }, {
+
+    _updateElement: function()
+    {
+        this._element.style.width = (this._currentRange * (100 / this._ranges)) + &quot;%&quot;;
+    },
+
+    incrementRange: function()
+    {
+        ++this._currentRange;
+        this._updateElement();
+    }
+});
+
</ins><span class="cx"> Utilities.extendObject(window.benchmarkRunnerClient, {
</span><span class="cx">     testsCount: null,
</span><span class="cx">     progressBar: null,
</span></span></pre></div>
<a id="trunkPerformanceTestsAnimometerresourcesextensionsjs"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/Animometer/resources/extensions.js (196227 => 196228)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/Animometer/resources/extensions.js        2016-02-07 00:18:40 UTC (rev 196227)
+++ trunk/PerformanceTests/Animometer/resources/extensions.js        2016-02-07 00:27:12 UTC (rev 196228)
</span><span class="lines">@@ -1,3 +1,62 @@
</span><ins>+Utilities =
+{
+    _parse: function(str, sep)
+    {
+        var output = {};
+        str.split(sep).forEach(function(part) {
+            var item = part.split(&quot;=&quot;);
+            var value = decodeURIComponent(item[1]);
+            if (value[0] == &quot;'&quot; )
+                output[item[0]] = value.substr(1, value.length - 2);
+            else
+                output[item[0]] = value;
+          });
+        return output;
+    },
+
+    parseParameters: function()
+    {
+        return this._parse(window.location.search.substr(1), &quot;&amp;&quot;);
+    },
+
+    parseArguments: function(str)
+    {
+        return this._parse(str, &quot; &quot;);
+    },
+
+    extendObject: function(obj1, obj2)
+    {
+        for (var attrname in obj2)
+            obj1[attrname] = obj2[attrname];
+        return obj1;
+    },
+
+    copyObject: function(obj)
+    {
+        return this.extendObject({}, obj);
+    },
+
+    mergeObjects: function(obj1, obj2)
+    {
+        return this.extendObject(this.copyObject(obj1), obj2);
+    },
+
+    createClass: function(classConstructor, classMethods)
+    {
+        classConstructor.prototype = classMethods;
+        return classConstructor;
+    },
+
+    createSubclass: function(superclass, classConstructor, classMethods)
+    {
+        classConstructor.prototype = Object.create(superclass.prototype);
+        classConstructor.prototype.constructor = classConstructor;
+        if (classMethods)
+            Utilities.extendObject(classConstructor.prototype, classMethods);
+        return classConstructor;
+    }
+};
+
</ins><span class="cx"> Array.prototype.swap = function(i, j)
</span><span class="cx"> {
</span><span class="cx">     var t = this[i];
</span><span class="lines">@@ -57,35 +116,13 @@
</span><span class="cx">     return this;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-function Point(x, y)
-{
-    this.x = x;
-    this.y = y;
-}
</del><ins>+Point = Utilities.createClass(
+    function(x, y)
+    {
+        this.x = x;
+        this.y = y;
+    }, {
</ins><span class="cx"> 
</span><del>-Point.zero = function()
-{
-    return new Point(0, 0);
-}
-
-Point.pointOnCircle = function(angle, radius)
-{
-    return new Point(radius * Math.cos(angle), radius * Math.sin(angle));
-}
-
-Point.pointOnEllipse = function(angle, radiuses)
-{
-    return new Point(radiuses.x * Math.cos(angle), radiuses.y * Math.sin(angle));
-}
-
-Point.elementClientSize = function(element)
-{
-    var rect = element.getBoundingClientRect();
-    return new Point(rect.width, rect.height);
-}
-
-Point.prototype =
-{
</del><span class="cx">     // Used when the point object is used as a size object.
</span><span class="cx">     get width()
</span><span class="cx">     {
</span><span class="lines">@@ -145,28 +182,40 @@
</span><span class="cx">         this.y /= l;
</span><span class="cx">         return this;
</span><span class="cx">     }
</span><del>-};
</del><ins>+});
</ins><span class="cx"> 
</span><del>-function Insets(top, right, bottom, left)
-{
-    this.top = top;
-    this.right = right;
-    this.bottom = bottom;
-    this.left = left;
-}
</del><ins>+Utilities.extendObject(Point, {
+    zero: function()
+    {
+        return new Point(0, 0);
+    },
</ins><span class="cx"> 
</span><del>-Insets.elementPadding = function(element)
-{
-    var styles = window.getComputedStyle(element);
-    return new Insets(
-        parseFloat(styles.paddingTop),
-        parseFloat(styles.paddingRight),
-        parseFloat(styles.paddingBottom),
-        parseFloat(styles.paddingTop));
-}
</del><ins>+    pointOnCircle: function(angle, radius)
+    {
+        return new Point(radius * Math.cos(angle), radius * Math.sin(angle));
+    },
</ins><span class="cx"> 
</span><del>-Insets.prototype =
-{
</del><ins>+    pointOnEllipse: function(angle, radiuses)
+    {
+        return new Point(radiuses.x * Math.cos(angle), radiuses.y * Math.sin(angle));
+    },
+
+    elementClientSize: function(element)
+    {
+        var rect = element.getBoundingClientRect();
+        return new Point(rect.width, rect.height);
+    }
+});
+
+Insets = Utilities.createClass(
+    function(top, right, bottom, left)
+    {
+        this.top = top;
+        this.right = right;
+        this.bottom = bottom;
+        this.left = left;
+    }, {
+
</ins><span class="cx">     get width()
</span><span class="cx">     {
</span><span class="cx">         return this.left + this.right;
</span><span class="lines">@@ -181,45 +230,57 @@
</span><span class="cx">     {
</span><span class="cx">         return new Point(this.width, this.height);
</span><span class="cx">     }
</span><del>-}
</del><ins>+});
</ins><span class="cx"> 
</span><del>-function SimplePromise()
</del><ins>+Insets.elementPadding = function(element)
</ins><span class="cx"> {
</span><del>-    this._chainedPromise = null;
-    this._callback = null;
</del><ins>+    var styles = window.getComputedStyle(element);
+    return new Insets(
+        parseFloat(styles.paddingTop),
+        parseFloat(styles.paddingRight),
+        parseFloat(styles.paddingBottom),
+        parseFloat(styles.paddingTop));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-SimplePromise.prototype.then = function (callback)
-{
-    if (this._callback)
-        throw &quot;SimplePromise doesn't support multiple calls to then&quot;;
</del><ins>+SimplePromise = Utilities.createClass(
+    function()
+    {
+        this._chainedPromise = null;
+        this._callback = null;
+    }, {
</ins><span class="cx"> 
</span><del>-    this._callback = callback;
-    this._chainedPromise = new SimplePromise;
</del><ins>+    then: function (callback)
+    {
+        if (this._callback)
+            throw &quot;SimplePromise doesn't support multiple calls to then&quot;;
</ins><span class="cx"> 
</span><del>-    if (this._resolved)
-        this.resolve(this._resolvedValue);
</del><ins>+        this._callback = callback;
+        this._chainedPromise = new SimplePromise;
</ins><span class="cx"> 
</span><del>-    return this._chainedPromise;
-}
</del><ins>+        if (this._resolved)
+            this.resolve(this._resolvedValue);
</ins><span class="cx"> 
</span><del>-SimplePromise.prototype.resolve = function (value)
-{
-    if (!this._callback) {
-        this._resolved = true;
-        this._resolvedValue = value;
-        return;
-    }
</del><ins>+        return this._chainedPromise;
+    },
</ins><span class="cx"> 
</span><del>-    var result = this._callback(value);
-    if (result instanceof SimplePromise) {
-        var chainedPromise = this._chainedPromise;
-        result.then(function (result) { chainedPromise.resolve(result); });
-    } else
-        this._chainedPromise.resolve(result);
-}
</del><ins>+    resolve: function (value)
+    {
+        if (!this._callback) {
+            this._resolved = true;
+            this._resolvedValue = value;
+            return;
+        }
</ins><span class="cx"> 
</span><del>-var Statistics =
</del><ins>+        var result = this._callback(value);
+        if (result instanceof SimplePromise) {
+            var chainedPromise = this._chainedPromise;
+            result.then(function (result) { chainedPromise.resolve(result); });
+        } else
+            this._chainedPromise.resolve(result);
+    }
+});
+
+Statistics =
</ins><span class="cx"> {
</span><span class="cx">     sampleMean: function(numberOfSamples, sum)
</span><span class="cx">     {
</span><span class="lines">@@ -246,7 +307,7 @@
</span><span class="cx">     }
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-window.DocumentExtension =
</del><ins>+DocumentExtension =
</ins><span class="cx"> {
</span><span class="cx">     createElement: function(name, attrs, parentElement)
</span><span class="cx">     {
</span><span class="lines">@@ -275,315 +336,4 @@
</span><span class="cx">         parentElement.appendChild(element);
</span><span class="cx">         return element;
</span><span class="cx">     }
</span><del>-}
-
-function ProgressBar(element, ranges)
-{
-    this._element = element;
-    this._ranges = ranges;
-    this._currentRange = 0;
-    this._updateElement();
-}
-
-ProgressBar.prototype =
-{
-    _updateElement: function()
-    {
-        this._element.style.width = (this._currentRange * (100 / this._ranges)) + &quot;%&quot;;
-    },
-
-    incrementRange: function()
-    {
-        ++this._currentRange;
-        this._updateElement();
-    }
-}
-
-function ResultsDashboard()
-{
-    this._iterationsSamplers = [];
-    this._processedData = undefined;
-}
-
-ResultsDashboard.prototype =
-{
-    push: function(suitesSamplers)
-    {
-        this._iterationsSamplers.push(suitesSamplers);
-    },
-
-    _processData: function()
-    {
-        var iterationsResults = [];
-        var iterationsScores = [];
-
-        this._iterationsSamplers.forEach(function(iterationSamplers, index) {
-            var suitesResults = {};
-            var suitesScores = [];
-
-            for (var suiteName in iterationSamplers) {
-                var suite = suiteFromName(suiteName);
-                var suiteSamplerData = iterationSamplers[suiteName];
-
-                var testsResults = {};
-                var testsScores = [];
-
-                for (var testName in suiteSamplerData) {
-                    testsResults[testName] = suiteSamplerData[testName];
-                    testsScores.push(testsResults[testName][Strings.json.score]);
-                }
-
-                suitesResults[suiteName] =  {};
-                suitesResults[suiteName][Strings.json.score] = Statistics.geometricMean(testsScores);
-                suitesResults[suiteName][Strings.json.results.tests] = testsResults;
-                suitesScores.push(suitesResults[suiteName][Strings.json.score]);
-            }
-
-            iterationsResults[index] = {};
-            iterationsResults[index][Strings.json.score] = Statistics.geometricMean(suitesScores);
-            iterationsResults[index][Strings.json.results.suites] = suitesResults;
-            iterationsScores.push(iterationsResults[index][Strings.json.score]);
-        });
-
-        this._processedData = {};
-        this._processedData[Strings.json.score] = Statistics.sampleMean(iterationsScores.length, iterationsScores.reduce(function(a, b) { return a * b; }));
-        this._processedData[Strings.json.results.iterations] = iterationsResults;
-    },
-
-    get data()
-    {
-        if (this._processedData)
-            return this._processedData;
-        this._processData();
-        return this._processedData;
-    },
-
-    get score()
-    {
-        return this.data[Strings.json.score];
-    }
-}
-
-function ResultsTable(element, headers)
-{
-    this.element = element;
-    this._headers = headers;
-
-    this._flattenedHeaders = [];
-    this._headers.forEach(function(header) {
-        if (header.children)
-            this._flattenedHeaders = this._flattenedHeaders.concat(header.children);
-        else
-            this._flattenedHeaders.push(header);
-    }, this);
-
-    this.clear();
-}
-
-ResultsTable.prototype =
-{
-    clear: function()
-    {
-        this.element.innerHTML = &quot;&quot;;
-    },
-
-    _addHeader: function()
-    {
-        var thead = DocumentExtension.createElement(&quot;thead&quot;, {}, this.element);
-        var row = DocumentExtension.createElement(&quot;tr&quot;, {}, thead);
-
-        this._headers.forEach(function (header) {
-            var th = DocumentExtension.createElement(&quot;th&quot;, {}, row);
-            if (header.title != Strings.text.results.graph)
-                th.textContent = header.title;
-            if (header.children)
-                th.colSpan = header.children.length;
-        });
-    },
-
-    _addGraphButton: function(td, testName, testResults)
-    {
-        var data = testResults[Strings.json.samples];
-        if (!data)
-            return;
-
-        var button = DocumentExtension.createElement(&quot;button&quot;, { class: &quot;small-button&quot; }, td);
-
-        button.addEventListener(&quot;click&quot;, function() {
-            var score = testResults[Strings.json.score].toFixed(2);
-            var complexity = testResults[Strings.json.experiments.complexity];
-            var mean = [
-                &quot;mean: &quot;,
-                complexity[Strings.json.measurements.average].toFixed(2),
-                &quot; ± &quot;,
-                complexity[Strings.json.measurements.stdev].toFixed(2),
-                &quot; (&quot;,
-                complexity[Strings.json.measurements.percent].toFixed(2),
-                &quot;%), worst 5%: &quot;,
-                complexity[Strings.json.measurements.concern].toFixed(2)].join(&quot;&quot;);
-
-            var graphData = {
-                axes: [Strings.text.experiments.complexity, Strings.text.experiments.frameRate],
-                mean: [
-                    testResults[Strings.json.experiments.complexity][Strings.json.measurements.average],
-                    testResults[Strings.json.experiments.frameRate][Strings.json.measurements.average]
-                ],
-                samples: data,
-                samplingTimeOffset: testResults[Strings.json.samplingTimeOffset]
-            }
-            if (testResults[Strings.json.targetFPS])
-                graphData.targetFPS = testResults[Strings.json.targetFPS];
-            benchmarkController.showTestGraph(testName, score, mean, graphData);
-        });
-
-        button.textContent = Strings.text.results.graph + &quot;...&quot;;
-    },
-
-    _isNoisyMeasurement: function(jsonExperiment, data, measurement, options)
-    {
-        const percentThreshold = 10;
-        const averageThreshold = 2;
-
-        if (measurement == Strings.json.measurements.percent)
-            return data[Strings.json.measurements.percent] &gt;= percentThreshold;
-
-        if (jsonExperiment == Strings.json.experiments.frameRate &amp;&amp; measurement == Strings.json.measurements.average)
-            return Math.abs(data[Strings.json.measurements.average] - options[&quot;frame-rate&quot;]) &gt;= averageThreshold;
-
-        return false;
-    },
-
-    _addEmptyRow: function()
-    {
-        var row = DocumentExtension.createElement(&quot;tr&quot;, {}, this.element);
-        this._flattenedHeaders.forEach(function (header) {
-            return DocumentExtension.createElement(&quot;td&quot;, { class: &quot;suites-separator&quot; }, row);
-        });
-    },
-
-    _addTest: function(testName, testResults, options)
-    {
-        var row = DocumentExtension.createElement(&quot;tr&quot;, {}, this.element);
-
-        var isNoisy = false;
-        [Strings.json.experiments.complexity, Strings.json.experiments.frameRate].forEach(function (experiment) {
-            var data = testResults[experiment];
-            for (var measurement in data) {
-                if (this._isNoisyMeasurement(experiment, data, measurement, options))
-                    isNoisy = true;
-            }
-        }, this);
-
-        this._flattenedHeaders.forEach(function (header) {
-            var className = &quot;&quot;;
-            if (header.className) {
-                if (typeof header.className == &quot;function&quot;)
-                    className = header.className(testResults, options);
-                else
-                    className = header.className;
-            }
-
-            if (header.title == Strings.text.testName) {
-                var titleClassName = className;
-                if (isNoisy)
-                    titleClassName += &quot; noisy-results&quot;;
-                var td = DocumentExtension.createElement(&quot;td&quot;, { class: titleClassName }, row);
-                td.textContent = testName;
-                return;
-            }
-
-            var td = DocumentExtension.createElement(&quot;td&quot;, { class: className }, row);
-            if (header.title == Strings.text.results.graph) {
-                this._addGraphButton(td, testName, testResults);
-            } else if (!(&quot;text&quot; in header)) {
-                td.textContent = testResults[header.title];
-            } else if (typeof header.text == &quot;string&quot;) {
-                var data = testResults[header.text];
-                if (typeof data == &quot;number&quot;)
-                    data = data.toFixed(2);
-                td.textContent = data;
-            } else {
-                td.textContent = header.text(testResults, testName);
-            }
-        }, this);
-    },
-
-    _addSuite: function(suiteName, suiteResults, options)
-    {
-        for (var testName in suiteResults[Strings.json.results.tests]) {
-            var testResults = suiteResults[Strings.json.results.tests][testName];
-            this._addTest(testName, testResults, options);
-        }
-    },
-
-    _addIteration: function(iterationResult, options)
-    {
-        for (var suiteName in iterationResult[Strings.json.results.suites]) {
-            this._addEmptyRow();
-            this._addSuite(suiteName, iterationResult[Strings.json.results.suites][suiteName], options);
-        }
-    },
-
-    showIterations: function(iterationsResults, options)
-    {
-        this.clear();
-        this._addHeader();
-
-        iterationsResults.forEach(function(iterationResult) {
-            this._addIteration(iterationResult, options);
-        }, this);
-    }
-}
-
-window.Utilities =
-{
-    _parse: function(str, sep)
-    {
-        var output = {};
-        str.split(sep).forEach(function(part) {
-            var item = part.split(&quot;=&quot;);
-            var value = decodeURIComponent(item[1]);
-            if (value[0] == &quot;'&quot; )
-                output[item[0]] = value.substr(1, value.length - 2);
-            else
-                output[item[0]] = value;
-          });
-        return output;
-    },
-
-    parseParameters: function()
-    {
-        return this._parse(window.location.search.substr(1), &quot;&amp;&quot;);
-    },
-
-    parseArguments: function(str)
-    {
-        return this._parse(str, &quot; &quot;);
-    },
-
-    extendObject: function(obj1, obj2)
-    {
-        for (var attrname in obj2)
-            obj1[attrname] = obj2[attrname];
-        return obj1;
-    },
-
-    copyObject: function(obj)
-    {
-        return this.extendObject({}, obj);
-    },
-
-    mergeObjects: function(obj1, obj2)
-    {
-        return this.extendObject(this.copyObject(obj1), obj2);
-    },
-
-    createSubclass: function(superclass, classConstructor, extend)
-    {
-        classConstructor.prototype = Object.create(superclass.prototype);
-        classConstructor.prototype.constructor = classConstructor;
-        if (extend)
-            Utilities.extendObject(classConstructor.prototype, extend);
-        return classConstructor;
-    }
-}
</del><ins>+};
</ins></span></pre></div>
<a id="trunkPerformanceTestsAnimometerresourcesrunneranimometerjs"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/Animometer/resources/runner/animometer.js (196227 => 196228)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/Animometer/resources/runner/animometer.js        2016-02-07 00:18:40 UTC (rev 196227)
+++ trunk/PerformanceTests/Animometer/resources/runner/animometer.js        2016-02-07 00:27:12 UTC (rev 196228)
</span><span class="lines">@@ -1,3 +1,237 @@
</span><ins>+ResultsDashboard = Utilities.createClass(
+    function()
+    {
+        this._iterationsSamplers = [];
+        this._processedData = undefined;
+    }, {
+
+    push: function(suitesSamplers)
+    {
+        this._iterationsSamplers.push(suitesSamplers);
+    },
+
+    _processData: function()
+    {
+        var iterationsResults = [];
+        var iterationsScores = [];
+
+        this._iterationsSamplers.forEach(function(iterationSamplers, index) {
+            var suitesResults = {};
+            var suitesScores = [];
+
+            for (var suiteName in iterationSamplers) {
+                var suite = suiteFromName(suiteName);
+                var suiteSamplerData = iterationSamplers[suiteName];
+
+                var testsResults = {};
+                var testsScores = [];
+
+                for (var testName in suiteSamplerData) {
+                    testsResults[testName] = suiteSamplerData[testName];
+                    testsScores.push(testsResults[testName][Strings.json.score]);
+                }
+
+                suitesResults[suiteName] =  {};
+                suitesResults[suiteName][Strings.json.score] = Statistics.geometricMean(testsScores);
+                suitesResults[suiteName][Strings.json.results.tests] = testsResults;
+                suitesScores.push(suitesResults[suiteName][Strings.json.score]);
+            }
+
+            iterationsResults[index] = {};
+            iterationsResults[index][Strings.json.score] = Statistics.geometricMean(suitesScores);
+            iterationsResults[index][Strings.json.results.suites] = suitesResults;
+            iterationsScores.push(iterationsResults[index][Strings.json.score]);
+        });
+
+        this._processedData = {};
+        this._processedData[Strings.json.score] = Statistics.sampleMean(iterationsScores.length, iterationsScores.reduce(function(a, b) { return a * b; }));
+        this._processedData[Strings.json.results.iterations] = iterationsResults;
+    },
+
+    get data()
+    {
+        if (this._processedData)
+            return this._processedData;
+        this._processData();
+        return this._processedData;
+    },
+
+    get score()
+    {
+        return this.data[Strings.json.score];
+    }
+});
+
+ResultsTable = Utilities.createClass(
+    function(element, headers)
+    {
+        this.element = element;
+        this._headers = headers;
+
+        this._flattenedHeaders = [];
+        this._headers.forEach(function(header) {
+            if (header.children)
+                this._flattenedHeaders = this._flattenedHeaders.concat(header.children);
+            else
+                this._flattenedHeaders.push(header);
+        }, this);
+
+        this.clear();
+    }, {
+
+    clear: function()
+    {
+        this.element.innerHTML = &quot;&quot;;
+    },
+
+    _addHeader: function()
+    {
+        var thead = DocumentExtension.createElement(&quot;thead&quot;, {}, this.element);
+        var row = DocumentExtension.createElement(&quot;tr&quot;, {}, thead);
+
+        this._headers.forEach(function (header) {
+            var th = DocumentExtension.createElement(&quot;th&quot;, {}, row);
+            if (header.title != Strings.text.results.graph)
+                th.textContent = header.title;
+            if (header.children)
+                th.colSpan = header.children.length;
+        });
+    },
+
+    _addGraphButton: function(td, testName, testResults)
+    {
+        var data = testResults[Strings.json.samples];
+        if (!data)
+            return;
+
+        var button = DocumentExtension.createElement(&quot;button&quot;, { class: &quot;small-button&quot; }, td);
+
+        button.addEventListener(&quot;click&quot;, function() {
+            var score = testResults[Strings.json.score].toFixed(2);
+            var complexity = testResults[Strings.json.experiments.complexity];
+            var mean = [
+                &quot;mean: &quot;,
+                complexity[Strings.json.measurements.average].toFixed(2),
+                &quot; ± &quot;,
+                complexity[Strings.json.measurements.stdev].toFixed(2),
+                &quot; (&quot;,
+                complexity[Strings.json.measurements.percent].toFixed(2),
+                &quot;%), worst 5%: &quot;,
+                complexity[Strings.json.measurements.concern].toFixed(2)].join(&quot;&quot;);
+
+            var graphData = {
+                axes: [Strings.text.experiments.complexity, Strings.text.experiments.frameRate],
+                mean: [
+                    testResults[Strings.json.experiments.complexity][Strings.json.measurements.average],
+                    testResults[Strings.json.experiments.frameRate][Strings.json.measurements.average]
+                ],
+                samples: data,
+                samplingTimeOffset: testResults[Strings.json.samplingTimeOffset]
+            }
+            if (testResults[Strings.json.targetFPS])
+                graphData.targetFPS = testResults[Strings.json.targetFPS];
+            benchmarkController.showTestGraph(testName, score, mean, graphData);
+        });
+
+        button.textContent = Strings.text.results.graph + &quot;...&quot;;
+    },
+
+    _isNoisyMeasurement: function(jsonExperiment, data, measurement, options)
+    {
+        const percentThreshold = 10;
+        const averageThreshold = 2;
+
+        if (measurement == Strings.json.measurements.percent)
+            return data[Strings.json.measurements.percent] &gt;= percentThreshold;
+
+        if (jsonExperiment == Strings.json.experiments.frameRate &amp;&amp; measurement == Strings.json.measurements.average)
+            return Math.abs(data[Strings.json.measurements.average] - options[&quot;frame-rate&quot;]) &gt;= averageThreshold;
+
+        return false;
+    },
+
+    _addEmptyRow: function()
+    {
+        var row = DocumentExtension.createElement(&quot;tr&quot;, {}, this.element);
+        this._flattenedHeaders.forEach(function (header) {
+            return DocumentExtension.createElement(&quot;td&quot;, { class: &quot;suites-separator&quot; }, row);
+        });
+    },
+
+    _addTest: function(testName, testResults, options)
+    {
+        var row = DocumentExtension.createElement(&quot;tr&quot;, {}, this.element);
+
+        var isNoisy = false;
+        [Strings.json.experiments.complexity, Strings.json.experiments.frameRate].forEach(function (experiment) {
+            var data = testResults[experiment];
+            for (var measurement in data) {
+                if (this._isNoisyMeasurement(experiment, data, measurement, options))
+                    isNoisy = true;
+            }
+        }, this);
+
+        this._flattenedHeaders.forEach(function (header) {
+            var className = &quot;&quot;;
+            if (header.className) {
+                if (typeof header.className == &quot;function&quot;)
+                    className = header.className(testResults, options);
+                else
+                    className = header.className;
+            }
+
+            if (header.title == Strings.text.testName) {
+                var titleClassName = className;
+                if (isNoisy)
+                    titleClassName += &quot; noisy-results&quot;;
+                var td = DocumentExtension.createElement(&quot;td&quot;, { class: titleClassName }, row);
+                td.textContent = testName;
+                return;
+            }
+
+            var td = DocumentExtension.createElement(&quot;td&quot;, { class: className }, row);
+            if (header.title == Strings.text.results.graph) {
+                this._addGraphButton(td, testName, testResults);
+            } else if (!(&quot;text&quot; in header)) {
+                td.textContent = testResults[header.title];
+            } else if (typeof header.text == &quot;string&quot;) {
+                var data = testResults[header.text];
+                if (typeof data == &quot;number&quot;)
+                    data = data.toFixed(2);
+                td.textContent = data;
+            } else {
+                td.textContent = header.text(testResults, testName);
+            }
+        }, this);
+    },
+
+    _addSuite: function(suiteName, suiteResults, options)
+    {
+        for (var testName in suiteResults[Strings.json.results.tests]) {
+            var testResults = suiteResults[Strings.json.results.tests][testName];
+            this._addTest(testName, testResults, options);
+        }
+    },
+
+    _addIteration: function(iterationResult, options)
+    {
+        for (var suiteName in iterationResult[Strings.json.results.suites]) {
+            this._addEmptyRow();
+            this._addSuite(suiteName, iterationResult[Strings.json.results.suites][suiteName], options);
+        }
+    },
+
+    showIterations: function(iterationsResults, options)
+    {
+        this.clear();
+        this._addHeader();
+
+        iterationsResults.forEach(function(iterationResult) {
+            this._addIteration(iterationResult, options);
+        }, this);
+    }
+});
+
</ins><span class="cx"> window.benchmarkRunnerClient = {
</span><span class="cx">     iterationCount: 1,
</span><span class="cx">     options: null,
</span></span></pre></div>
<a id="trunkPerformanceTestsAnimometerresourcesrunnerbenchmarkrunnerjs"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/Animometer/resources/runner/benchmark-runner.js (196227 => 196228)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/Animometer/resources/runner/benchmark-runner.js        2016-02-07 00:18:40 UTC (rev 196227)
+++ trunk/PerformanceTests/Animometer/resources/runner/benchmark-runner.js        2016-02-07 00:27:12 UTC (rev 196228)
</span><span class="lines">@@ -1,12 +1,12 @@
</span><del>-function BenchmarkRunnerState(suites)
-{
-    this._suites = suites;
-    this._suiteIndex = -1;
-    this._testIndex = 0;
-    this.next();
-}
</del><ins>+BenchmarkRunnerState = Utilities.createClass(
+    function(suites)
+    {
+        this._suites = suites;
+        this._suiteIndex = -1;
+        this._testIndex = 0;
+        this.next();
+    }, {
</ins><span class="cx"> 
</span><del>-BenchmarkRunnerState.prototype = {
</del><span class="cx">     currentSuite: function()
</span><span class="cx">     {
</span><span class="cx">         return this._suites[this._suiteIndex];
</span><span class="lines">@@ -49,16 +49,16 @@
</span><span class="cx">         frame.src = &quot;tests/&quot; + test.url;
</span><span class="cx">         return promise;
</span><span class="cx">     }
</span><del>-};
</del><ins>+});
</ins><span class="cx"> 
</span><del>-function BenchmarkRunner(suites, frameContainer, client)
-{
-    this._suites = suites;
-    this._client = client;
-    this._frameContainer = frameContainer;
-}
</del><ins>+BenchmarkRunner = Utilities.createClass(
+    function(suites, frameContainer, client)
+    {
+        this._suites = suites;
+        this._client = client;
+        this._frameContainer = frameContainer;
+    }, {
</ins><span class="cx"> 
</span><del>-BenchmarkRunner.prototype = {
</del><span class="cx">     _appendFrame: function()
</span><span class="cx">     {
</span><span class="cx">         var frame = document.createElement(&quot;iframe&quot;);
</span><span class="lines">@@ -173,4 +173,4 @@
</span><span class="cx">         if (this._runNextIteration)
</span><span class="cx">             this._runNextIteration();
</span><span class="cx">     }
</span><del>-};
</del><ins>+});
</ins></span></pre></div>
<a id="trunkPerformanceTestsAnimometertestsmasterresourcescanvastestsjs"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/Animometer/tests/master/resources/canvas-tests.js (196227 => 196228)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/Animometer/tests/master/resources/canvas-tests.js        2016-02-07 00:18:40 UTC (rev 196227)
+++ trunk/PerformanceTests/Animometer/tests/master/resources/canvas-tests.js        2016-02-07 00:27:12 UTC (rev 196228)
</span><span class="lines">@@ -2,116 +2,122 @@
</span><span class="cx"> 
</span><span class="cx"> // === PAINT OBJECTS ===
</span><span class="cx"> 
</span><del>-function CanvasLineSegment(stage)
-{
-    var circle = Stage.randomInt(0, 2);
-    this._color = [&quot;#e01040&quot;, &quot;#10c030&quot;, &quot;#e05010&quot;][circle];
-    this._lineWidth = Math.pow(Math.random(), 12) * 20 + 3;
-    this._omega = Math.random() * 3 + 0.2;
-    var theta = Stage.randomAngle();
-    this._cosTheta = Math.cos(theta);
-    this._sinTheta = Math.sin(theta);
-    this._startX = stage.circleRadius * this._cosTheta + (0.5 + circle) / 3 * stage.size.x;
-    this._startY = stage.circleRadius * this._sinTheta + stage.size.y / 2;
-    this._length = Math.pow(Math.random(), 8) * 40 + 20;
-    this._segmentDirection = Math.random() &gt; 0.5 ? -1 : 1;
-}
</del><ins>+CanvasLineSegment = Utilities.createClass(
+    function(stage)
+    {
+        var circle = Stage.randomInt(0, 2);
+        this._color = [&quot;#e01040&quot;, &quot;#10c030&quot;, &quot;#e05010&quot;][circle];
+        this._lineWidth = Math.pow(Math.random(), 12) * 20 + 3;
+        this._omega = Math.random() * 3 + 0.2;
+        var theta = Stage.randomAngle();
+        this._cosTheta = Math.cos(theta);
+        this._sinTheta = Math.sin(theta);
+        this._startX = stage.circleRadius * this._cosTheta + (0.5 + circle) / 3 * stage.size.x;
+        this._startY = stage.circleRadius * this._sinTheta + stage.size.y / 2;
+        this._length = Math.pow(Math.random(), 8) * 40 + 20;
+        this._segmentDirection = Math.random() &gt; 0.5 ? -1 : 1;
+    }, {
</ins><span class="cx"> 
</span><del>-CanvasLineSegment.prototype.draw = function(context)
-{
-    context.strokeStyle = this._color;
-    context.lineWidth = this._lineWidth;
</del><ins>+    draw: function(context)
+    {
+        context.strokeStyle = this._color;
+        context.lineWidth = this._lineWidth;
</ins><span class="cx"> 
</span><del>-    this._length += Math.sin(Date.now()/100*this._omega);
</del><ins>+        this._length += Math.sin(Date.now()/100*this._omega);
</ins><span class="cx"> 
</span><del>-    context.beginPath();
-    context.moveTo(this._startX, this._startY);
-    context.lineTo(this._startX + this._segmentDirection * this._length * this._cosTheta,
-                   this._startY + this._segmentDirection * this._length * this._sinTheta);
-    context.stroke();
-};
</del><ins>+        context.beginPath();
+        context.moveTo(this._startX, this._startY);
+        context.lineTo(this._startX + this._segmentDirection * this._length * this._cosTheta,
+                       this._startY + this._segmentDirection * this._length * this._sinTheta);
+        context.stroke();
+    }
+});
</ins><span class="cx"> 
</span><del>-function CanvasArc(stage)
-{
-    var maxX = 6, maxY = 3;
-    var distanceX = stage.size.x / maxX;
-    var distanceY = stage.size.y / (maxY + 1);
-    var randY = Stage.randomInt(0, maxY);
-    var randX = Stage.randomInt(0, maxX - 1 * (randY % 2));
</del><ins>+CanvasArc = Utilities.createClass(
+    function(stage)
+    {
+        var maxX = 6, maxY = 3;
+        var distanceX = stage.size.x / maxX;
+        var distanceY = stage.size.y / (maxY + 1);
+        var randY = Stage.randomInt(0, maxY);
+        var randX = Stage.randomInt(0, maxX - 1 * (randY % 2));
</ins><span class="cx"> 
</span><del>-    this._point = new Point(distanceX * (randX + (randY % 2) / 2), distanceY * (randY + .5));
</del><ins>+        this._point = new Point(distanceX * (randX + (randY % 2) / 2), distanceY * (randY + .5));
</ins><span class="cx"> 
</span><del>-    this._radius = 20 + Math.pow(Math.random(), 5) * (Math.min(distanceX, distanceY) / 1.8);
-    this._startAngle = Stage.randomAngle();
-    this._endAngle = Stage.randomAngle();
-    this._omega = (Math.random() - 0.5) * 0.3;
-    this._counterclockwise = Stage.randomBool();
-    var colors = [&quot;#101010&quot;, &quot;#808080&quot;, &quot;#c0c0c0&quot;];
-    colors.push([&quot;#e01040&quot;, &quot;#10c030&quot;, &quot;#e05010&quot;][(randX + Math.ceil(randY / 2)) % 3]);
-    this._color = colors[Math.floor(Math.random() * colors.length)];
-    this._lineWidth = 1 + Math.pow(Math.random(), 5) * 30;
-    this._doStroke = Stage.randomInt(0, 3) != 0;
-};
</del><ins>+        this._radius = 20 + Math.pow(Math.random(), 5) * (Math.min(distanceX, distanceY) / 1.8);
+        this._startAngle = Stage.randomAngle();
+        this._endAngle = Stage.randomAngle();
+        this._omega = (Math.random() - 0.5) * 0.3;
+        this._counterclockwise = Stage.randomBool();
+        var colors = [&quot;#101010&quot;, &quot;#808080&quot;, &quot;#c0c0c0&quot;];
+        colors.push([&quot;#e01040&quot;, &quot;#10c030&quot;, &quot;#e05010&quot;][(randX + Math.ceil(randY / 2)) % 3]);
+        this._color = colors[Math.floor(Math.random() * colors.length)];
+        this._lineWidth = 1 + Math.pow(Math.random(), 5) * 30;
+        this._doStroke = Stage.randomInt(0, 3) != 0;
+    }, {
</ins><span class="cx"> 
</span><del>-CanvasArc.prototype.draw = function(context)
-{
-    this._startAngle += this._omega;
-    this._endAngle += this._omega / 2;
</del><ins>+    draw: function(context)
+    {
+        this._startAngle += this._omega;
+        this._endAngle += this._omega / 2;
</ins><span class="cx"> 
</span><del>-    if (this._doStroke) {
-        context.strokeStyle = this._color;
-        context.lineWidth = this._lineWidth;
-        context.beginPath();
-        context.arc(this._point.x, this._point.y, this._radius, this._startAngle, this._endAngle, this._counterclockwise);
-        context.stroke();
-    } else {
-        context.fillStyle = this._color;
-        context.beginPath();
-        context.lineTo(this._point.x, this._point.y);
-        context.arc(this._point.x, this._point.y, this._radius, this._startAngle, this._endAngle, this._counterclockwise);
-        context.lineTo(this._point.x, this._point.y);
-        context.fill();
</del><ins>+        if (this._doStroke) {
+            context.strokeStyle = this._color;
+            context.lineWidth = this._lineWidth;
+            context.beginPath();
+            context.arc(this._point.x, this._point.y, this._radius, this._startAngle, this._endAngle, this._counterclockwise);
+            context.stroke();
+        } else {
+            context.fillStyle = this._color;
+            context.beginPath();
+            context.lineTo(this._point.x, this._point.y);
+            context.arc(this._point.x, this._point.y, this._radius, this._startAngle, this._endAngle, this._counterclockwise);
+            context.lineTo(this._point.x, this._point.y);
+            context.fill();
+        }
</ins><span class="cx">     }
</span><del>-};
</del><ins>+});
</ins><span class="cx"> 
</span><span class="cx"> // CanvasLinePoint contains no draw() method since it is either moveTo or
</span><span class="cx"> // lineTo depending on its index.
</span><del>-function CanvasLinePoint(stage, coordinateMaximum)
-{
-    var X_LOOPS = 40;
-    var Y_LOOPS = 20;
</del><ins>+CanvasLinePoint = Utilities.createClass(
+    function(stage, coordinateMaximum)
+    {
+        var X_LOOPS = 40;
+        var Y_LOOPS = 20;
</ins><span class="cx"> 
</span><del>-    var offsets = [[-2, -1], [2, 1], [-1, 0], [1, 0], [-1, 2], [1, -2]];
-    var offset = offsets[Math.floor(Math.random() * offsets.length)];
</del><ins>+        var offsets = [[-2, -1], [2, 1], [-1, 0], [1, 0], [-1, 2], [1, -2]];
+        var offset = offsets[Math.floor(Math.random() * offsets.length)];
</ins><span class="cx"> 
</span><del>-    this.coordinate = new Point(X_LOOPS/2, Y_LOOPS/2);
-    if (stage.objects.length) {
-        var head = stage.objects[stage.objects.length - 1].coordinate;
-        this.coordinate.x = head.x;
-        this.coordinate.y = head.y;
-    }
</del><ins>+        this.coordinate = new Point(X_LOOPS/2, Y_LOOPS/2);
+        if (stage.objects.length) {
+            var head = stage.objects[stage.objects.length - 1].coordinate;
+            this.coordinate.x = head.x;
+            this.coordinate.y = head.y;
+        }
</ins><span class="cx"> 
</span><del>-    var nextCoordinate = this.coordinate.x + offset[0];
-    if (nextCoordinate &lt; 0 || nextCoordinate &gt; X_LOOPS)
-        this.coordinate.x -= offset[0];
-    else
-        this.coordinate.x = nextCoordinate;
-    nextCoordinate = this.coordinate.y + offset[1];
-    if (nextCoordinate &lt; 0 || nextCoordinate &gt; Y_LOOPS)
-        this.coordinate.y -= offset[1];
-    else
-        this.coordinate.y = nextCoordinate;
</del><ins>+        var nextCoordinate = this.coordinate.x + offset[0];
+        if (nextCoordinate &lt; 0 || nextCoordinate &gt; X_LOOPS)
+            this.coordinate.x -= offset[0];
+        else
+            this.coordinate.x = nextCoordinate;
+        nextCoordinate = this.coordinate.y + offset[1];
+        if (nextCoordinate &lt; 0 || nextCoordinate &gt; Y_LOOPS)
+            this.coordinate.y -= offset[1];
+        else
+            this.coordinate.y = nextCoordinate;
</ins><span class="cx"> 
</span><del>-    var xOff = .25 * (this.coordinate.y % 2);
-    var randX = (xOff + this.coordinate.x) * stage.size.x / X_LOOPS;
-    var randY = this.coordinate.y * stage.size.y / Y_LOOPS;
-    var colors = [&quot;#101010&quot;, &quot;#808080&quot;, &quot;#c0c0c0&quot;, &quot;#101010&quot;, &quot;#808080&quot;, &quot;#c0c0c0&quot;, &quot;#e01040&quot;];
-    this.color = colors[Math.floor(Math.random() * colors.length)];
</del><ins>+        var xOff = .25 * (this.coordinate.y % 2);
+        var randX = (xOff + this.coordinate.x) * stage.size.x / X_LOOPS;
+        var randY = this.coordinate.y * stage.size.y / Y_LOOPS;
+        var colors = [&quot;#101010&quot;, &quot;#808080&quot;, &quot;#c0c0c0&quot;, &quot;#101010&quot;, &quot;#808080&quot;, &quot;#c0c0c0&quot;, &quot;#e01040&quot;];
+        this.color = colors[Math.floor(Math.random() * colors.length)];
</ins><span class="cx"> 
</span><del>-    this.width = Math.pow(Math.random(), 5) * 20 + 1;
-    this.isSplit = Math.random() &gt; 0.9;
-    this.point = new Point(randX, randY);
-}
</del><ins>+        this.width = Math.pow(Math.random(), 5) * 20 + 1;
+        this.isSplit = Math.random() &gt; 0.9;
+        this.point = new Point(randX, randY);
+    }
+);
</ins><span class="cx"> 
</span><span class="cx"> // === STAGES ===
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkPerformanceTestsAnimometertestsresourcesmainjs"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/Animometer/tests/resources/main.js (196227 => 196228)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/Animometer/tests/resources/main.js        2016-02-07 00:18:40 UTC (rev 196227)
+++ trunk/PerformanceTests/Animometer/tests/resources/main.js        2016-02-07 00:27:12 UTC (rev 196228)
</span><span class="lines">@@ -1,11 +1,11 @@
</span><del>-function Rotater(rotateInterval)
-{
-    this._timeDelta = 0;
-    this._rotateInterval = rotateInterval;
-}
</del><ins>+Rotater = Utilities.createClass(
+    function(rotateInterval)
+    {
+        this._timeDelta = 0;
+        this._rotateInterval = rotateInterval;
+        this._isSampling = false;
+    }, {
</ins><span class="cx"> 
</span><del>-Rotater.prototype =
-{
</del><span class="cx">     get interval()
</span><span class="cx">     {
</span><span class="cx">         return this._rotateInterval;
</span><span class="lines">@@ -30,7 +30,7 @@
</span><span class="cx">     {
</span><span class="cx">         return &quot;rotate(&quot; + Math.floor(this.degree()) + &quot;, &quot; + center.x + &quot;,&quot; + center.y + &quot;)&quot;;
</span><span class="cx">     }
</span><del>-};
</del><ins>+});
</ins><span class="cx"> 
</span><span class="cx"> function BenchmarkState(testInterval)
</span><span class="cx"> {
</span><span class="lines">@@ -82,8 +82,51 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-function Stage() {}
</del><ins>+Stage = Utilities.createClass(
+    function()
+    {
+    }, {
</ins><span class="cx"> 
</span><ins>+    initialize: function(benchmark)
+    {
+        this._benchmark = benchmark;
+        this._element = document.getElementById(&quot;stage&quot;);
+        this._element.setAttribute(&quot;width&quot;, document.body.offsetWidth);
+        this._element.setAttribute(&quot;height&quot;, document.body.offsetHeight);
+        this._size = Point.elementClientSize(this._element).subtract(Insets.elementPadding(this._element).size);
+    },
+
+    get element()
+    {
+        return this._element;
+    },
+
+    get size()
+    {
+        return this._size;
+    },
+
+    complexity: function()
+    {
+        return 0;
+    },
+
+    tune: function()
+    {
+        throw &quot;Not implemented&quot;;
+    },
+
+    animate: function()
+    {
+        throw &quot;Not implemented&quot;;
+    },
+
+    clear: function()
+    {
+        return this.tune(-this.tune(0));
+    }
+});
+
</ins><span class="cx"> Utilities.extendObject(Stage, {
</span><span class="cx">     random: function(min, max)
</span><span class="cx">     {
</span><span class="lines">@@ -137,58 +180,15 @@
</span><span class="cx">     }
</span><span class="cx"> });
</span><span class="cx"> 
</span><del>-Stage.prototype =
-{
-    initialize: function(benchmark)
</del><ins>+Animator = Utilities.createClass(
+    function()
</ins><span class="cx">     {
</span><del>-        this._benchmark = benchmark;
-        this._element = document.getElementById(&quot;stage&quot;);
-        this._element.setAttribute(&quot;width&quot;, document.body.offsetWidth);
-        this._element.setAttribute(&quot;height&quot;, document.body.offsetHeight);
-        this._size = Point.elementClientSize(this._element).subtract(Insets.elementPadding(this._element).size);
-    },
</del><ins>+        this._intervalFrameCount = 0;
+        this._numberOfFramesToMeasurePerInterval = 3;
+        this._referenceTime = 0;
+        this._currentTimeOffset = 0;
+    }, {
</ins><span class="cx"> 
</span><del>-    get element()
-    {
-        return this._element;
-    },
-
-    get size()
-    {
-        return this._size;
-    },
-
-    complexity: function()
-    {
-        return 0;
-    },
-
-    tune: function()
-    {
-        throw &quot;Not implemented&quot;;
-    },
-
-    animate: function()
-    {
-        throw &quot;Not implemented&quot;;
-    },
-
-    clear: function()
-    {
-        return this.tune(-this.tune(0));
-    }
-};
-
-function Animator()
-{
-    this._intervalFrameCount = 0;
-    this._numberOfFramesToMeasurePerInterval = 3;
-    this._referenceTime = 0;
-    this._currentTimeOffset = 0;
-}
-
-Animator.prototype =
-{
</del><span class="cx">     initialize: function(benchmark)
</span><span class="cx">     {
</span><span class="cx">         this._benchmark = benchmark;
</span><span class="lines">@@ -257,26 +257,25 @@
</span><span class="cx">             requestAnimationFrame(this.animateLoop.bind(this));
</span><span class="cx">         }
</span><span class="cx">     }
</span><del>-}
</del><ins>+});
</ins><span class="cx"> 
</span><del>-function Benchmark(stage, options)
-{
-    this._options = options;
</del><ins>+Benchmark = Utilities.createClass(
+    function(stage, options)
+    {
+        this._options = options;
</ins><span class="cx"> 
</span><del>-    this._stage = stage;
-    this._stage.initialize(this);
-    this._animator = new Animator();
-    this._animator.initialize(this);
</del><ins>+        this._stage = stage;
+        this._stage.initialize(this);
+        this._animator = new Animator();
+        this._animator.initialize(this);
</ins><span class="cx"> 
</span><del>-    this._recordInterval = 200;
-    this._isSampling = false;
-    this._controller = new PIDController(this._options[&quot;frame-rate&quot;]);
-    this._sampler = new Sampler(4, 60 * this._options[&quot;test-interval&quot;], this);
-    this._state = new BenchmarkState(this._options[&quot;test-interval&quot;] * 1000);
-}
</del><ins>+        this._recordInterval = 200;
+        this._isSampling = false;
+        this._controller = new PIDController(this._options[&quot;frame-rate&quot;]);
+        this._sampler = new Sampler(4, 60 * this._options[&quot;test-interval&quot;], this);
+        this._state = new BenchmarkState(this._options[&quot;test-interval&quot;] * 1000);
+    }, {
</ins><span class="cx"> 
</span><del>-Benchmark.prototype =
-{
</del><span class="cx">     get options()
</span><span class="cx">     {
</span><span class="cx">         return this._options;
</span><span class="lines">@@ -423,4 +422,4 @@
</span><span class="cx">             results[jsonExperiment][Strings.json.measurements.percent] = experiment.percentage();
</span><span class="cx">         });
</span><span class="cx">     }
</span><del>-};
</del><ins>+});
</ins></span></pre></div>
<a id="trunkPerformanceTestsAnimometertestsresourcessamplerjs"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/Animometer/tests/resources/sampler.js (196227 => 196228)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/Animometer/tests/resources/sampler.js        2016-02-07 00:18:40 UTC (rev 196227)
+++ trunk/PerformanceTests/Animometer/tests/resources/sampler.js        2016-02-07 00:27:12 UTC (rev 196228)
</span><span class="lines">@@ -1,19 +1,12 @@
</span><del>-function Experiment()
-{
-    this._sum = 0;
-    this._squareSum = 0;
-    this._numberOfSamples = 0;
-    this._maxHeap = Algorithm.createMaxHeap(Experiment.defaults.CONCERN_SIZE);
-}
</del><ins>+Experiment = Utilities.createClass(
+    function()
+    {
+        this._sum = 0;
+        this._squareSum = 0;
+        this._numberOfSamples = 0;
+        this._maxHeap = Algorithm.createMaxHeap(Experiment.defaults.CONCERN_SIZE);
+    }, {
</ins><span class="cx"> 
</span><del>-Experiment.defaults =
-{
-    CONCERN: 5,
-    CONCERN_SIZE: 100,
-}
-
-Experiment.prototype =
-{
</del><span class="cx">     sample: function(value)
</span><span class="cx">     {
</span><span class="cx">         this._sum += value;
</span><span class="lines">@@ -49,24 +42,29 @@
</span><span class="cx">     {
</span><span class="cx">         return Statistics.geometricMean([this.mean(), Math.max(this.concern(percentage), 1)]);
</span><span class="cx">     }
</span><del>-}
</del><ins>+});
</ins><span class="cx"> 
</span><del>-function Sampler(seriesCount, expectedSampleCount, processor)
</del><ins>+Experiment.defaults =
</ins><span class="cx"> {
</span><del>-    this._processor = processor;
-
-    this.samples = [];
-    for (var i = 0; i &lt; seriesCount; ++i) {
-        var array = new Array(expectedSampleCount);
-        array.fill(0);
-        this.samples[i] = array;
-    }
-    this.sampleCount = 0;
-    this.marks = {};
</del><ins>+    CONCERN: 5,
+    CONCERN_SIZE: 100,
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-Sampler.prototype =
-{
</del><ins>+Sampler = Utilities.createClass(
+    function(seriesCount, expectedSampleCount, processor)
+    {
+        this._processor = processor;
+
+        this.samples = [];
+        for (var i = 0; i &lt; seriesCount; ++i) {
+            var array = new Array(expectedSampleCount);
+            array.fill(0);
+            this.samples[i] = array;
+        }
+        this.sampleCount = 0;
+        this.marks = {};
+    }, {
+
</ins><span class="cx">     record: function() {
</span><span class="cx">         // Assume that arguments.length == this.samples.length
</span><span class="cx">         for (var i = 0; i &lt; arguments.length; i++) {
</span><span class="lines">@@ -99,4 +97,4 @@
</span><span class="cx"> 
</span><span class="cx">         return results;
</span><span class="cx">     }
</span><del>-}
</del><ins>+});
</ins></span></pre></div>
<a id="trunkPerformanceTestsAnimometertestssimpleresourcessimplecanvaspathsjs"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/Animometer/tests/simple/resources/simple-canvas-paths.js (196227 => 196228)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/Animometer/tests/simple/resources/simple-canvas-paths.js        2016-02-07 00:18:40 UTC (rev 196227)
+++ trunk/PerformanceTests/Animometer/tests/simple/resources/simple-canvas-paths.js        2016-02-07 00:27:12 UTC (rev 196228)
</span><span class="lines">@@ -2,177 +2,213 @@
</span><span class="cx"> 
</span><span class="cx"> // === PAINT OBJECTS ===
</span><span class="cx"> 
</span><del>-function CanvasLineSegment(stage) {
-    var radius = Stage.randomInt(10, 100);
-    var center = Stage.randomPosition(stage.size);
-    var delta = Point.pointOnCircle(Stage.randomAngle(), radius/2);
</del><ins>+CanvasLineSegment = Utilities.createClass(
+    function(stage) {
+        var radius = Stage.randomInt(10, 100);
+        var center = Stage.randomPosition(stage.size);
+        var delta = Point.pointOnCircle(Stage.randomAngle(), radius/2);
</ins><span class="cx"> 
</span><del>-    this._point1 = center.add(delta);
-    this._point2 = center.subtract(delta);
-    this._color = Stage.randomColor();
-    this._lineWidth = Stage.randomInt(1, 100);
-}
-CanvasLineSegment.prototype.draw = function(context) {
-    context.strokeStyle = this._color;
-    context.lineWidth = this._lineWidth;
-    context.beginPath();
-    context.moveTo(this._point1.x, this._point1.y);
-    context.lineTo(this._point2.x, this._point2.y);
-    context.stroke();
-};
</del><ins>+        this._point1 = center.add(delta);
+        this._point2 = center.subtract(delta);
+        this._color = Stage.randomColor();
+        this._lineWidth = Stage.randomInt(1, 100);
+    }, {
</ins><span class="cx"> 
</span><del>-function CanvasLinePoint(stage, coordinateMaximumFactor) {
-    var pointMaximum = new Point(Math.min(stage.size.x, coordinateMaximumFactor * stage.size.x), Math.min(stage.size.y, coordinateMaximumFactor * stage.size.y));
-    this._point = Stage.randomPosition(pointMaximum).add(new Point((stage.size.x - pointMaximum.x) / 2, (stage.size.y - pointMaximum.y) / 2));
-}
-CanvasLinePoint.prototype.draw = function(context) {
-    context.lineTo(this._point.x, this._point.y);
-};
</del><ins>+    draw: function(context) {
+        context.strokeStyle = this._color;
+        context.lineWidth = this._lineWidth;
+        context.beginPath();
+        context.moveTo(this._point1.x, this._point1.y);
+        context.lineTo(this._point2.x, this._point2.y);
+        context.stroke();
+    }
+});
</ins><span class="cx"> 
</span><del>-function CanvasQuadraticSegment(stage) {
-    var maxSize = Stage.randomInt(20, 200);
-    var toCenter = Stage.randomPosition(stage.size).subtract(new Point(maxSize/2, maxSize/2));
</del><ins>+CanvasLinePoint = Utilities.createClass(
+    function(stage, coordinateMaximumFactor) {
+        var pointMaximum = new Point(Math.min(stage.size.x, coordinateMaximumFactor * stage.size.x), Math.min(stage.size.y, coordinateMaximumFactor * stage.size.y));
+        this._point = Stage.randomPosition(pointMaximum).add(new Point((stage.size.x - pointMaximum.x) / 2, (stage.size.y - pointMaximum.y) / 2));
+    }, {
</ins><span class="cx"> 
</span><del>-    this._point1 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
-    this._point2 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
-    this._point3 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
-    this._color = Stage.randomColor();
-    this._lineWidth = Stage.randomInt(1, 50);
-};
-CanvasQuadraticSegment.prototype.draw = function(context) {
-    context.strokeStyle = this._color;
-    context.lineWidth = this._lineWidth;
-    context.beginPath();
-    context.moveTo(this._point1.x, this._point1.y);
-    context.quadraticCurveTo(this._point2.x, this._point2.y, this._point3.x, this._point3.y);
-    context.stroke();
-};
</del><ins>+    draw: function(context) {
+        context.lineTo(this._point.x, this._point.y);
+    }
+})
</ins><span class="cx"> 
</span><del>-function CanvasQuadraticPoint(stage, coordinateMaximumFactor) {
-    var pointMaximum = Stage.randomPosition(new Point(Math.min(stage.size.x, coordinateMaximumFactor * stage.size.x), Math.min(stage.size.y, coordinateMaximumFactor * stage.size.y)));
-    this._point1 = Stage.randomPosition(pointMaximum).add(new Point((stage.size.x - pointMaximum.x) / 2, (stage.size.y - pointMaximum.y) / 2));
-    this._point2 = Stage.randomPosition(pointMaximum).add(new Point((stage.size.x - pointMaximum.x) / 2, (stage.size.y - pointMaximum.y) / 2));
-};
-CanvasQuadraticPoint.prototype.draw = function(context) {
-    context.quadraticCurveTo(this._point1.x, this._point1.y, this._point2.x, this._point2.y);
-};
</del><ins>+CanvasQuadraticSegment = Utilities.createClass(
+    function(stage) {
+        var maxSize = Stage.randomInt(20, 200);
+        var toCenter = Stage.randomPosition(stage.size).subtract(new Point(maxSize/2, maxSize/2));
</ins><span class="cx"> 
</span><del>-function CanvasBezierSegment(stage) {
-    var maxSize = Stage.randomInt(20, 200);
-    var toCenter = Stage.randomPosition(stage.size).subtract(new Point(maxSize/2, maxSize/2));
</del><ins>+        this._point1 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
+        this._point2 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
+        this._point3 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
+        this._color = Stage.randomColor();
+        this._lineWidth = Stage.randomInt(1, 50);
+    }, {
</ins><span class="cx"> 
</span><del>-    this._point1 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
-    this._point2 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
-    this._point3 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
-    this._point4 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
-    this._color = Stage.randomColor();
-    this._lineWidth = Stage.randomInt(1, 50);
-};
-CanvasBezierSegment.prototype.draw = function(context) {
-    context.strokeStyle = this._color;
-    context.lineWidth = this._lineWidth;
-    context.beginPath();
-    context.moveTo(this._point1.x, this._point1.y);
-    context.bezierCurveTo(this._point2.x, this._point2.y, this._point3.x, this._point3.y, this._point4.x, this._point4.y);
-    context.stroke();
-};
</del><ins>+    draw: function(context) {
+        context.strokeStyle = this._color;
+        context.lineWidth = this._lineWidth;
+        context.beginPath();
+        context.moveTo(this._point1.x, this._point1.y);
+        context.quadraticCurveTo(this._point2.x, this._point2.y, this._point3.x, this._point3.y);
+        context.stroke();
+    }
+});
</ins><span class="cx"> 
</span><del>-function CanvasBezierPoint(stage, coordinateMaximumFactor) {
-    var pointMaximum = Stage.randomPosition(new Point(Math.min(stage.size.x, coordinateMaximumFactor * stage.size.x), Math.min(stage.size.y, coordinateMaximumFactor * stage.size.y)));
-    this._point1 = Stage.randomPosition(pointMaximum).add(new Point((stage.size.x - pointMaximum.x) / 2, (stage.size.y - pointMaximum.y) / 2));
-    this._point2 = Stage.randomPosition(pointMaximum).add(new Point((stage.size.x - pointMaximum.x) / 2, (stage.size.y - pointMaximum.y) / 2));
-    this._point3 = Stage.randomPosition(pointMaximum).add(new Point((stage.size.x - pointMaximum.x) / 2, (stage.size.y - pointMaximum.y) / 2));
-};
-CanvasBezierPoint.prototype.draw = function(context) {
-    context.bezierCurveTo(this._point1.x, this._point1.y, this._point2.x, this._point2.y, this._point3.x, this._point3.y);
-};
</del><ins>+CanvasQuadraticPoint = Utilities.createClass(
+    function(stage, coordinateMaximumFactor) {
+        var pointMaximum = Stage.randomPosition(new Point(Math.min(stage.size.x, coordinateMaximumFactor * stage.size.x), Math.min(stage.size.y, coordinateMaximumFactor * stage.size.y)));
+        this._point1 = Stage.randomPosition(pointMaximum).add(new Point((stage.size.x - pointMaximum.x) / 2, (stage.size.y - pointMaximum.y) / 2));
+        this._point2 = Stage.randomPosition(pointMaximum).add(new Point((stage.size.x - pointMaximum.x) / 2, (stage.size.y - pointMaximum.y) / 2));
+    }, {
</ins><span class="cx"> 
</span><del>-function CanvasArcToSegment(stage) {
-    var maxSize = Stage.randomInt(20, 200);
-    var toCenter = Stage.randomPosition(stage.size).subtract(new Point(maxSize/2, maxSize/2));
</del><ins>+    draw: function(context) {
+        context.quadraticCurveTo(this._point1.x, this._point1.y, this._point2.x, this._point2.y);
+    }
+});
</ins><span class="cx"> 
</span><del>-    this._point1 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
-    this._point2 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
-    this._point3 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
-    this._radius = Stage.randomInt(20, 200);
-    this._color = Stage.randomColor();
-    this._lineWidth = Stage.randomInt(1, 50);
-};
-CanvasArcToSegment.prototype.draw = function(context) {
-    context.strokeStyle = this._color;
-    context.lineWidth = this._lineWidth;
-    context.beginPath();
-    context.moveTo(this._point1.x, this._point1.y);
-    context.arcTo(this._point2.x, this._point2.y, this._point3.x, this._point3.y, this._radius);
-    context.stroke();
-};
</del><ins>+CanvasBezierSegment = Utilities.createClass(
+    function(stage) {
+        var maxSize = Stage.randomInt(20, 200);
+        var toCenter = Stage.randomPosition(stage.size).subtract(new Point(maxSize/2, maxSize/2));
</ins><span class="cx"> 
</span><del>-function CanvasArcToSegmentFill(stage) {
-    CanvasArcToSegment.call(this, stage);
-};
-CanvasArcToSegmentFill.prototype.draw = function(context) {
-    context.fillStyle = this._color;
-    context.beginPath();
-    context.moveTo(this._point1.x, this._point1.y);
-    context.arcTo(this._point2.x, this._point2.y, this._point3.x, this._point3.y, this._radius);
-    context.fill();
-};
</del><ins>+        this._point1 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
+        this._point2 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
+        this._point3 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
+        this._point4 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
+        this._color = Stage.randomColor();
+        this._lineWidth = Stage.randomInt(1, 50);
+    }, {
</ins><span class="cx"> 
</span><del>-function CanvasArcSegment(stage) {
-    var maxSize = Stage.randomInt(20, 200);
-    var toCenter = Stage.randomPosition(stage.size).subtract(new Point(maxSize/2, maxSize/2));
</del><ins>+    draw: function(context) {
+        context.strokeStyle = this._color;
+        context.lineWidth = this._lineWidth;
+        context.beginPath();
+        context.moveTo(this._point1.x, this._point1.y);
+        context.bezierCurveTo(this._point2.x, this._point2.y, this._point3.x, this._point3.y, this._point4.x, this._point4.y);
+        context.stroke();
+    }
+});
</ins><span class="cx"> 
</span><del>-    this._point = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
-    this._radius = Stage.randomInt(20, 200);
-    this._startAngle = Stage.randomAngle();
-    this._endAngle = Stage.randomAngle();
-    this._counterclockwise = Stage.randomBool();
-    this._color = Stage.randomColor();
-    this._lineWidth = Stage.randomInt(1, 50);
-};
-CanvasArcSegment.prototype.draw = function(context) {
-    context.strokeStyle = this._color;
-    context.lineWidth = this._lineWidth;
-    context.beginPath();
-    context.arc(this._point.x, this._point.y, this._radius, this._startAngle, this._endAngle, this._counterclockwise);
-    context.stroke();
-};
</del><ins>+CanvasBezierPoint = Utilities.createClass(
+    function(stage, coordinateMaximumFactor) {
+        var pointMaximum = Stage.randomPosition(new Point(Math.min(stage.size.x, coordinateMaximumFactor * stage.size.x), Math.min(stage.size.y, coordinateMaximumFactor * stage.size.y)));
+        this._point1 = Stage.randomPosition(pointMaximum).add(new Point((stage.size.x - pointMaximum.x) / 2, (stage.size.y - pointMaximum.y) / 2));
+        this._point2 = Stage.randomPosition(pointMaximum).add(new Point((stage.size.x - pointMaximum.x) / 2, (stage.size.y - pointMaximum.y) / 2));
+        this._point3 = Stage.randomPosition(pointMaximum).add(new Point((stage.size.x - pointMaximum.x) / 2, (stage.size.y - pointMaximum.y) / 2));
+    }, {
</ins><span class="cx"> 
</span><del>-function CanvasArcSegmentFill(stage) {
-    CanvasArcSegment.call(this, stage);
-};
-CanvasArcSegmentFill.prototype.draw = function(context) {
-    context.fillStyle = this._color;
-    context.beginPath();
-    context.arc(this._point.x, this._point.y, this._radius, this._startAngle, this._endAngle, this._counterclockwise);
-    context.fill();
-};
</del><ins>+    draw: function(context) {
+        context.bezierCurveTo(this._point1.x, this._point1.y, this._point2.x, this._point2.y, this._point3.x, this._point3.y);
+    }
+});
</ins><span class="cx"> 
</span><del>-function CanvasRect(stage) {
-    this._width = Stage.randomInt(20, 200);
-    this._height = Stage.randomInt(20, 200);
-    this._point = Stage.randomPosition(stage.size).subtract(new Point(this._width/2, this._height/2));
-    this._color = Stage.randomColor();
-    this._lineWidth = Stage.randomInt(1, 20);
-}
-CanvasRect.prototype.draw = function(context) {
-    context.strokeStyle = this._color;
-    context.lineWidth = this._lineWidth;
-    context.beginPath();
-    context.rect(this._point.x, this._point.y, this._width, this._height);
-    context.stroke();
-};
</del><ins>+CanvasArcToSegment = Utilities.createClass(
+    function(stage) {
+        var maxSize = Stage.randomInt(20, 200);
+        var toCenter = Stage.randomPosition(stage.size).subtract(new Point(maxSize/2, maxSize/2));
</ins><span class="cx"> 
</span><del>-function CanvasRectFill(stage) {
-    CanvasRect.call(this, stage);
-}
-CanvasRectFill.prototype.draw = function(context) {
-    context.fillStyle = this._color;
-    context.beginPath();
-    context.rect(this._point.x, this._point.y, this._width, this._height);
-    context.fill();
-};
</del><ins>+        this._point1 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
+        this._point2 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
+        this._point3 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
+        this._radius = Stage.randomInt(20, 200);
+        this._color = Stage.randomColor();
+        this._lineWidth = Stage.randomInt(1, 50);
+    }, {
</ins><span class="cx"> 
</span><ins>+    draw: function(context) {
+        context.strokeStyle = this._color;
+        context.lineWidth = this._lineWidth;
+        context.beginPath();
+        context.moveTo(this._point1.x, this._point1.y);
+        context.arcTo(this._point2.x, this._point2.y, this._point3.x, this._point3.y, this._radius);
+        context.stroke();
+    }
+});
+
+CanvasArcToSegmentFill = Utilities.createClass(
+    function(stage) {
+        CanvasArcToSegment.call(this, stage);
+    }, {
+
+    draw: function(context) {
+        context.fillStyle = this._color;
+        context.beginPath();
+        context.moveTo(this._point1.x, this._point1.y);
+        context.arcTo(this._point2.x, this._point2.y, this._point3.x, this._point3.y, this._radius);
+        context.fill();
+    }
+});
+
+CanvasArcSegment = Utilities.createClass(
+    function(stage) {
+        var maxSize = Stage.randomInt(20, 200);
+        var toCenter = Stage.randomPosition(stage.size).subtract(new Point(maxSize/2, maxSize/2));
+
+        this._point = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
+        this._radius = Stage.randomInt(20, 200);
+        this._startAngle = Stage.randomAngle();
+        this._endAngle = Stage.randomAngle();
+        this._counterclockwise = Stage.randomBool();
+        this._color = Stage.randomColor();
+        this._lineWidth = Stage.randomInt(1, 50);
+    }, {
+
+    draw: function(context) {
+        context.strokeStyle = this._color;
+        context.lineWidth = this._lineWidth;
+        context.beginPath();
+        context.arc(this._point.x, this._point.y, this._radius, this._startAngle, this._endAngle, this._counterclockwise);
+        context.stroke();
+    }
+});
+
+CanvasArcSegmentFill = Utilities.createClass(
+    function(stage) {
+        CanvasArcSegment.call(this, stage);
+    }, {
+
+    draw: function(context) {
+        context.fillStyle = this._color;
+        context.beginPath();
+        context.arc(this._point.x, this._point.y, this._radius, this._startAngle, this._endAngle, this._counterclockwise);
+        context.fill();
+    }
+});
+
+CanvasRect = Utilities.createClass(
+    function(stage) {
+        this._width = Stage.randomInt(20, 200);
+        this._height = Stage.randomInt(20, 200);
+        this._point = Stage.randomPosition(stage.size).subtract(new Point(this._width/2, this._height/2));
+        this._color = Stage.randomColor();
+        this._lineWidth = Stage.randomInt(1, 20);
+    }, {
+
+    draw: function(context) {
+        context.strokeStyle = this._color;
+        context.lineWidth = this._lineWidth;
+        context.beginPath();
+        context.rect(this._point.x, this._point.y, this._width, this._height);
+        context.stroke();
+    }
+});
+
+CanvasRectFill = Utilities.createClass(
+    function(stage) {
+        CanvasRect.call(this, stage);
+    }, {
+
+    draw: function(context) {
+        context.fillStyle = this._color;
+        context.beginPath();
+        context.rect(this._point.x, this._point.y, this._width, this._height);
+        context.fill();
+    }
+});
+
</ins><span class="cx"> // === STAGES ===
</span><span class="cx"> 
</span><span class="cx"> SimpleCanvasPathStrokeStage = Utilities.createSubclass(SimpleCanvasStage,
</span></span></pre></div>
<a id="trunkPerformanceTestsAnimometertestssimpleresourcestiledcanvasimagejs"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/Animometer/tests/simple/resources/tiled-canvas-image.js (196227 => 196228)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/Animometer/tests/simple/resources/tiled-canvas-image.js        2016-02-07 00:18:40 UTC (rev 196227)
+++ trunk/PerformanceTests/Animometer/tests/simple/resources/tiled-canvas-image.js        2016-02-07 00:27:12 UTC (rev 196228)
</span><span class="lines">@@ -1,21 +1,23 @@
</span><span class="cx"> (function() {
</span><span class="cx"> 
</span><del>-function CanvasImageTile(stage, source)
-{
-    this._context = stage.context;
-    this._size = stage.tileSize;
-    this.source = source;
-}
</del><ins>+CanvasImageTile = Utilities.createClass(
+    function(stage, source)
+    {
+        this._context = stage.context;
+        this._size = stage.tileSize;
+        this.source = source;
+    }, {
</ins><span class="cx"> 
</span><del>-CanvasImageTile.prototype.getImageData = function()
-{
-    this._imagedata = this._context.getImageData(this.source.x, this.source.y, this._size.width, this._size.height);
-}
</del><ins>+    getImageData: function()
+    {
+        this._imagedata = this._context.getImageData(this.source.x, this.source.y, this._size.width, this._size.height);
+    },
</ins><span class="cx"> 
</span><del>-CanvasImageTile.prototype.putImageData = function(destination)
-{
-    this._context.putImageData(this._imagedata, destination.x, destination.y);
-}
</del><ins>+    putImageData: function(destination)
+    {
+        this._context.putImageData(this._imagedata, destination.x, destination.y);
+    }
+});
</ins><span class="cx"> 
</span><span class="cx"> TiledCanvasImageStage = Utilities.createSubclass(Stage,
</span><span class="cx">     function(element, options)
</span><span class="lines">@@ -62,7 +64,7 @@
</span><span class="cx">     {
</span><span class="cx">         this._ctiles += count;
</span><span class="cx"> 
</span><del>-        this._ctiles = Math.max(this._ctiles, 0);    
</del><ins>+        this._ctiles = Math.max(this._ctiles, 0);
</ins><span class="cx">         this._ctiles = Math.min(this._ctiles, this._tiles.length);
</span><span class="cx"> 
</span><span class="cx">         return this._ctiles;
</span><span class="lines">@@ -100,7 +102,7 @@
</span><span class="cx">         for (var index = 0; index &lt; this._ctiles; ++index)
</span><span class="cx">             this._tiles[index].putImageData(destinations[index]);
</span><span class="cx">     },
</span><del>-    
</del><ins>+
</ins><span class="cx">     complexity: function()
</span><span class="cx">     {
</span><span class="cx">         return this._ctiles;
</span></span></pre></div>
<a id="trunkPerformanceTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/ChangeLog (196227 => 196228)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/ChangeLog        2016-02-07 00:18:40 UTC (rev 196227)
+++ trunk/PerformanceTests/ChangeLog        2016-02-07 00:27:12 UTC (rev 196228)
</span><span class="lines">@@ -1,5 +1,36 @@
</span><span class="cx"> 2016-02-06  Jon Lee  &lt;jonlee@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        Add a convenience function for creating a class.
+
+        The pattern for creating a class is common enough to add as a Utilities
+        helper function. It also makes it easy to collapse class definitions when
+        editing.
+
+        * Animometer/resources/debug-runner/animometer.js: Move ProgressBar definition,
+        since it is only used here.
+        * Animometer/resources/runner/animometer.js: Move ResultsDashboard and
+        ResultsTable definition, since it is only used here.
+        * Animometer/resources/extensions.js: Move Utilities definition to the top. Convert
+        Point, Insets, SimplePromise.
+        (ProgressBar): Moved to animometer.js.
+        (ResultsDashboard): Moved to animometer.js.
+        (ResultsTable): Moved to animometer.js.
+        * Animometer/resources/runner/benchmark-runner.js: Convert BenchmarkRunnerState,
+        BenchmarkRunner.
+        * Animometer/tests/resources/main.js: Convert Rotater, Stage, Animator, Benchmark.
+        * Animometer/tests/resources/sampler.js: Convert Experiment, Sampler.
+
+        Convert test primitives.
+        * Animometer/tests/master/resources/canvas-tests.js: Convert CanvasLineSegment,
+        CanvasArc, CanvasLinePoint.
+        * Animometer/tests/simple/resources/simple-canvas-paths.js: Convert CanvasLineSegment,
+        CanvasLinePoint, CanvasQuadraticSegment, CanvasQuadraticPoint, CanvasBezierSegment,
+        CanvasBezierPoint, CanvasArcToSegment, CanvasArcToSegmentFill, CanvasArcSegment,
+        CanvasArcSegmentFill, CanvasRect, CanvasRectFill.
+        * Animometer/tests/simple/resources/tiled-canvas-image.js: Convert CanvasImageTile.
+
+2016-02-06  Jon Lee  &lt;jonlee@apple.com&gt;
+
</ins><span class="cx">         Minor improvements to debug harness.
</span><span class="cx"> 
</span><span class="cx">         * Animometer/developer.html:
</span><span class="lines">@@ -48,15 +79,15 @@
</span><span class="cx">         and putImageData functions. This test draws a background on the canvas
</span><span class="cx">         and then gets some random tiles from this background and draw them in
</span><span class="cx">         destinations different from their original sources.
</span><del>-        
</del><ins>+
</ins><span class="cx">         * Animometer/resources/debug-runner/tests.js: Adding the new test to the canvas simple tests suite.
</span><del>-        
</del><ins>+
</ins><span class="cx">         * Animometer/resources/extensions.js:
</span><span class="cx">         (Array.prototype.shuffle): Shuffles the elements of an array.
</span><del>-        
</del><ins>+
</ins><span class="cx">         (Point.zero): Returns a new Point object whose x and y are equal zero.
</span><span class="cx">         (Point.prototype.str): Used for debugging the Point object.
</span><del>-        
</del><ins>+
</ins><span class="cx">         * Animometer/tests/simple/resources/tiled-canvas-image.js: Added.
</span><span class="cx">         (CanvasImageTile):
</span><span class="cx">         (CanvasImageTile.prototype.getImageData):
</span></span></pre>
</div>
</div>

</body>
</html>