summaryrefslogtreecommitdiffstats
path: root/third_party/webkit/PerformanceTests/MotionMark
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/webkit/PerformanceTests/MotionMark')
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/about.html52
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/developer.html175
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/index.html67
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/resources/debug-runner/animometer.css774
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/resources/debug-runner/animometer.js703
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/resources/debug-runner/d3.min.js5
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/resources/debug-runner/graph.js615
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/resources/debug-runner/tests.js345
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/resources/extensions.js670
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/resources/runner/animometer.css520
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/resources/runner/animometer.js626
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/resources/runner/benchmark-runner.js179
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/resources/runner/crystal.svg92
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/resources/runner/lines.svg26
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/resources/runner/logo.svg26
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/resources/runner/tests.js81
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/resources/statistics.js397
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/resources/strings.js51
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/3d/resources/webgl.js184
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/3d/webgl.html64
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-canvas-images.html26
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-canvas-shapes.html18
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-css-images.html22
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-css-shapes.html33
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-svg-images.html18
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-svg-shapes.html18
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-tagged-images.html22
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-canvas-images.js47
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-canvas-particles.js88
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-canvas-shapes.js87
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-css-images.js61
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-css-shapes.js86
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-particles.js123
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-svg-images.js43
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-svg-particles.js67
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-svg-shapes.js101
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-tagged-images.js106
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image1.jpgbin0 -> 64004 bytes
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image2.jpgbin0 -> 71981 bytes
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image3.jpgbin0 -> 71319 bytes
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image4.jpgbin0 -> 96373 bytes
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image5.jpgbin0 -> 135674 bytes
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/dom/compositing-transforms.html24
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/dom/focus.html51
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/dom/leaves.html26
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/dom/particles.html24
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/compositing-transforms.js66
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/dom-particles.js73
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/focus.js166
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/leaves.js48
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/canvas-stage.html17
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/focus.html29
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/image-data.html28
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/leaves.html25
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/multiply.html53
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/canvas-stage.js52
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/canvas-tests.js311
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/compass.svg7
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/compass100.pngbin0 -> 3048 bytes
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/console.svg6
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/console100.pngbin0 -> 944 bytes
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/contribute.svg6
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/contribute100.pngbin0 -> 3599 bytes
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/debugger.svg5
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/debugger100.pngbin0 -> 2473 bytes
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/focus.js129
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/image-data.js181
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/inspector.svg6
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/inspector100.pngbin0 -> 1477 bytes
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/layout.svg6
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/layout100.pngbin0 -> 423 bytes
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/leaves.js135
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/multiply.js119
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/particles.js112
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/performance.svg6
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/performance100.pngbin0 -> 2546 bytes
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/script.svg5
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/script100.pngbin0 -> 3192 bytes
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/shortcuts.svg5
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/shortcuts100.pngbin0 -> 2763 bytes
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/standards.svg6
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/standards100.pngbin0 -> 4363 bytes
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/storage.svg5
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/storage100.pngbin0 -> 3167 bytes
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/styles.svg5
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/styles100.pngbin0 -> 3875 bytes
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/svg-particles.js111
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/text.js116
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/timeline.svg6
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/timeline100.pngbin0 -> 2039 bytes
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/svg-particles.html38
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/master/text.html82
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/resources/main.js934
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/resources/math.js268
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/resources/stage.css27
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/resources/star.svg8
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/resources/yin-yang.pngbin0 -> 4082 bytes
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/resources/yin-yang.svg17
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/simple/resources/simple-canvas-paths.js453
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/simple/resources/simple-canvas.js35
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/simple/resources/tiled-canvas-image.js119
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/simple/simple-canvas-paths.html18
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/simple/tiled-canvas-image.html16
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/template/resources/template-canvas.js89
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/template/resources/template-css.js46
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/template/resources/template-svg.js46
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/template/template-canvas.html16
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/template/template-css.html16
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/tests/template/template-svg.html16
-rw-r--r--third_party/webkit/PerformanceTests/MotionMark/version2
110 files changed, 10834 insertions, 0 deletions
diff --git a/third_party/webkit/PerformanceTests/MotionMark/about.html b/third_party/webkit/PerformanceTests/MotionMark/about.html
new file mode 100644
index 0000000000..f14638a96b
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/about.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, user-scalable=no">
+
+ <title>About MotionMark</title>
+
+ <link rel="stylesheet" href="resources/runner/animometer.css">
+</head>
+<body class="images-loaded">
+ <main>
+ <section id="about" class="selected">
+ <svg class="logo"><use xlink:href="resources/runner/logo.svg#root"></svg>
+
+ <div class="body">
+ <h1>About MotionMark</h1>
+
+ <p>MotionMark is a web benchmark that focuses on graphics performance. It draws multiple rendering elements, each of which uses the same set of graphics primitives. An element could be an SVG node, an HTML element with CSS style, or a series of canvas operations. Slight variations among the elements avoid trivial caching optimizations by the browser. Although fairly simple, the effects were chosen to reflect techniques commonly used on the web. Tests are visually rich, being designed to stress the graphics system rather than JavaScript.</p>
+
+ <p>After an initial warm-up, each test runs for a fixed period of time. Based on measurements of the browser’s frame rate, MotionMark adjusts the number of elements to draw, and concentrates around a narrow range where the browser starts to fail animating at 60 frames per second (fps). A piecewise linear regression is applied to the data, and the change point is reported as the test's score. The confidence interval is calculated through <a href="https://en.wikipedia.org/wiki/Bootstrapping_(statistics)">bootstrapping</a>. MotionMark calculates the geometric mean of all of the tests’ scores to report the single score for the run.</p>
+
+ <p>MotionMark can be run on a wide variety of devices. Using the device’s screen dimensions it adjusts the drawing area into one of three sizes:</p>
+
+ <ol>
+ <li>Small (568 x 320), targeted at mobile phones</li>
+ <li>Medium (900 x 600), targeted at tablets and laptops</li>
+ <li>Large (1600 x 800), targeted at desktops</li>
+ </ol>
+
+ <p>The design of the benchmark is modular. This makes it easy to write new tests and use different controllers, which can assist a developer working on improving the performance of a web engine. For the purpose of a public benchmark, the MotionMark master suite tests a variety of drawing operations using techniques including CSS, SVG, and Canvas:</p>
+
+ <ul>
+ <li><strong>Multiply</strong>: CSS border radius, transforms, opacity</li>
+ <li><strong>Arcs and Fills</strong>: Canvas path fills and arcs</li>
+ <li><strong>Leaves</strong>: CSS-transformed elements</li>
+ <li><strong>Paths</strong>: Canvas line, quadratic, and Bezier paths</li>
+ <li><strong>Lines</strong>: Canvas line segments</li>
+ <li><strong>Focus</strong>: CSS blur filter, opacity</li>
+ <li><strong>Images</strong>: Canvas <code>getImageData()</code> and <code>putImageData()</code></li>
+ <li><strong>Design</strong>: HTML text rendering</li>
+ <li><strong>Suits</strong>: SVG clip paths, gradients and transforms</li>
+ </ul>
+
+ <p>To achieve consistent results on mobile devices, put the device in landscape orientation. On laptops and desktops, use the default display resolution and make the browser window fullscreen. Make sure that screen automatic display sleep is turned off or set to longer than 8 minutes.</p>
+
+ <center><button onclick="location.href='./'">Return to homepage</button></center>
+ </div>
+ </section>
+ </main>
+</body>
+</html> \ No newline at end of file
diff --git a/third_party/webkit/PerformanceTests/MotionMark/developer.html b/third_party/webkit/PerformanceTests/MotionMark/developer.html
new file mode 100644
index 0000000000..d7387a0e48
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/developer.html
@@ -0,0 +1,175 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, user-scalable=no">
+
+ <title>MotionMark 1.0 - developer</title>
+
+ <link rel="stylesheet" href="resources/runner/animometer.css">
+ <link rel="stylesheet" href="resources/debug-runner/animometer.css">
+
+ <script src="resources/strings.js"></script>
+ <script src="resources/extensions.js"></script>
+ <script src="resources/statistics.js"></script>
+
+ <script src="resources/runner/tests.js" charset="utf-8"></script>
+ <script src="resources/debug-runner/tests.js" charset="utf-8"></script>
+ <script src="resources/runner/animometer.js"></script>
+ <script src="resources/debug-runner/animometer.js" charset="utf-8"></script>
+
+ <script src="resources/runner/benchmark-runner.js"></script>
+ <script src="resources/debug-runner/d3.min.js"></script>
+ <script src="resources/debug-runner/graph.js" charset="utf-8"></script>
+</head>
+<body class="showing-intro">
+ <main>
+ <section id="intro" class="selected">
+ <h1>MotionMark</h1>
+ <div class="body">
+ <div>
+ <div id="suites">
+ <h2>Suites:</h2>
+ <ul class="tree"></ul>
+ <div><span id="drop-target">Drop results here</span></div>
+ </div>
+ <div id="options">
+ <h2>Options:</h2>
+ <form name="benchmark-options">
+ <ul>
+ <li>
+ <label>Test length: <input type="number" id="test-interval" value="30"> seconds each</label>
+ </li>
+ <li>
+ <h3>Display:</h3>
+ <ul>
+ <li><label><input name="display" type="radio" value="minimal" checked> Minimal</label></li>
+ <li><label><input name="display" type="radio" value="progress-bar"> Progress bar</label></li>
+ </ul>
+ </li>
+ <li>
+ <h3>Tiles:</h3>
+ <ul>
+ <li><label><input name="tiles" type="radio" value="big" checked> Big tiles</label></li>
+ <li><label><input name="tiles" type="radio" value="classic"> Classic tiles (512x512)</label></li>
+ </ul>
+ </li>
+ <li>
+ <h3>Adjusting the test complexity:</h3>
+ <ul>
+ <li><label><input name="controller" type="radio" value="fixed"> Keep at a fixed complexity</label></li>
+ <li><label><input name="controller" type="radio" value="step"> Keep at a fixed complexity, then make a big step</label></li>
+ <li><label><input name="controller" type="radio" value="adaptive"> Maintain target FPS</label></li>
+ <li><label><input name="controller" type="radio" value="ramp" checked> Ramp</label></li>
+ <li><label><input name="controller" type="radio" value="ramp30"> Ramp @ 30fps</label></li>
+ </ul>
+ </li>
+ <li>
+ <label>Target frame rate: <input type="number" id="frame-rate" value="50"> FPS</label>
+ </li>
+ <li>
+ <h3>Kalman filter estimated error:</h3>
+ <ul>
+ <li><label>Process error (Q): <input type="number" id="kalman-process-error" value="1"></label></li>
+ <li><label>Measurement error (R): <input type="number" id="kalman-measurement-error" value="4"></label></li>
+ </ul>
+ </li>
+ <li>
+ <h3>Time measurement method:</h3>
+ <ul>
+ <li><label><input name="time-measurement" type="radio" value="performance" checked> <code>performance.now()</code> (if available)</label></li>
+ <li><label><input name="time-measurement" type="radio" value="raf"> <code>requestAnimationFrame()</code> timestamp</label></li>
+ <li><label><input name="time-measurement" type="radio" value="date"> <code>Date.now()</code></label></li>
+ </ul>
+ </li>
+ </ul>
+ </form>
+ </div>
+ </div>
+ <p>For accurate results, please take the browser window full screen, or rotate the device to landscape orientation.</p>
+ <div class="start-benchmark">
+ <p class="hidden">Please rotate the device to orientation before starting.</p>
+ <button id="run-benchmark" onclick="benchmarkController.startBenchmark()">Run benchmark</button>
+ </div>
+ </div>
+ </section>
+
+ <section id="test-container">
+ <div id="running-test" class="frame-container"></div>
+ <div id="progress">
+ <div id="progress-completed"></div>
+ </div>
+ </section>
+
+ <section id="results">
+ <div class="body">
+ <h1>MotionMark score</h1>
+ <div class="detail">
+ <span class="small">on a small screen (phone)</span>
+ <span class="medium">on a medium screen (laptop, tablet)</span>
+ <span class="large">on a large screen (desktop)</span>
+ </div>
+ <p class="score" onclick="benchmarkController.showDebugInfo()"></p>
+ <p class="confidence"></p>
+ <div id="results-tables" class="table-container">
+ <div>
+ <table id="results-score"></table>
+ <table id="results-data"></table>
+ </div>
+ <table id="results-header"></table>
+ </div>
+ <button onclick="benchmarkController.restartBenchmark()">Test Again</button>
+ <p>
+ 'j': Show JSON results<br/>
+ 's': Select various results for copy/paste (use repeatedly to cycle)
+ </p>
+ </div>
+ </section>
+ <section id="test-graph">
+ <div class="body">
+ <header>
+ <button onclick="benchmarkController.showResults()">&lt; Results</button>
+ <h1>Graph:</h1>
+ <p class="score"></p>
+ <p class="confidence"></p>
+ </header>
+ <nav>
+ <form name="graph-type">
+ <ul>
+ <li><label><input type="radio" name="graph-type" value="time"> Time graph</label></li>
+ <li><label><input type="radio" name="graph-type" value="complexity" checked> Complexity graph</label></li>
+ </ul>
+ </form>
+ <form name="time-graph-options">
+ <ul>
+ <li><label><input type="checkbox" name="markers" checked> Markers</label>
+ <span>time: <span class="time"></span></span></li>
+ <li><label><input type="checkbox" name="averages" checked> Averages</label></li>
+ <li><label><input type="checkbox" name="complexity" checked> Complexity</label>
+ <span class="complexity"></span></li>
+ <li><label><input type="checkbox" name="rawFPS" checked> Raw FPS</label>
+ <span class="rawFPS"></span></li>
+ <li><label><input type="checkbox" name="filteredFPS" checked> Filtered FPS</label>
+ <span class="filteredFPS"></span></li>
+ <li><label><input type="checkbox" name="regressions" checked> Regressions</label></li>
+ </ul>
+ </form>
+ <form name="complexity-graph-options">
+ <ul class="series">
+ <li><label><input type="checkbox" name="series-raw" checked> Series raw</label></li>
+ <li><label><input type="checkbox" name="series-average"> Series average</label></li>
+ </ul>
+ <ul>
+ <li><label><input type="checkbox" name="regression-time-score"> Controller score</label></li>
+ <li><label><input type="checkbox" name="bootstrap-score" checked> Bootstrap score and histogram</label></li>
+ <li><label><input type="checkbox" name="complexity-regression-aggregate-raw" checked> Regression, series raw</label><span id="complexity-regression-aggregate-raw"></span></li>
+ <li><label><input type="checkbox" name="complexity-regression-aggregate-average"> Regression, series average</label><span id="complexity-regression-aggregate-average"></span></li>
+ </ul>
+ </form>
+ </nav>
+ <div id="test-graph-data"></div>
+ </div>
+ </section>
+ </main>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/index.html b/third_party/webkit/PerformanceTests/MotionMark/index.html
new file mode 100644
index 0000000000..c1b1e2e58f
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/index.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, user-scalable=no">
+
+ <title>MotionMark 1.0</title>
+
+ <link rel="stylesheet" href="resources/runner/animometer.css">
+
+ <script src="resources/strings.js" defer></script>
+ <script src="resources/extensions.js" defer></script>
+ <script src="resources/statistics.js" defer></script>
+
+ <script src="resources/runner/tests.js" charset="utf-8" defer></script>
+ <script src="resources/runner/animometer.js" defer></script>
+
+ <script src="resources/runner/benchmark-runner.js" defer></script>
+
+ <script>
+ window.addEventListener("load", function() {
+ // Start the fade in animation.
+ document.body.classList.add("images-loaded");
+ });
+ </script>
+</head>
+<body class="showing-intro">
+ <main>
+ <section id="intro" class="selected">
+ <svg class="logo"><use xlink:href="resources/runner/logo.svg#root"></svg>
+ <div class="body">
+ <p>MotionMark is a graphics benchmark that measures a browser’s capability to animate complex scenes at a target frame rate.</p>
+
+ <p><a href="about.html">More details</a> about the benchmark are available. Bigger scores are better.</p>
+ <p>For accurate results, please take your browser window full screen, or rotate your device to landscape orientation.</p>
+ <p class="portrait-orientation-check"><b>Please rotate your device.</b></p>
+ <button class="landscape-orientation-check" onclick="benchmarkController.startBenchmark()">Run Benchmark</button>
+ </div>
+ </section>
+
+ <section id="test-container" class="frame-container"></section>
+
+ <section id="results">
+ <svg class="logo"><use xlink:href="resources/runner/logo.svg#root"></svg>
+ <div class="body">
+ <div class="score-container">
+ <div class="score"></div>
+ <div class="confidence"></div>
+ <div class="detail">
+ <span class="small">on a small screen (phone)</span>
+ <span class="medium">on a medium screen (laptop, tablet)</span>
+ <span class="large">on a large screen (desktop)</span>
+ </div>
+ </div>
+ <div class="table-container">
+ <div>
+ <table id="results-score"></table>
+ <table id="results-data"></table>
+ </div>
+ <table id="results-header"></table>
+ </div>
+ <button onclick="benchmarkController.startBenchmark()">Test Again</button>
+ </div>
+ </section>
+ </main>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/resources/debug-runner/animometer.css b/third_party/webkit/PerformanceTests/MotionMark/resources/debug-runner/animometer.css
new file mode 100644
index 0000000000..7fbf31ee7d
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/resources/debug-runner/animometer.css
@@ -0,0 +1,774 @@
+body {
+ font-size: initial;
+}
+
+body.showing-intro,
+body.showing-results,
+body.showing-test-graph {
+ background-color: rgb(96, 96, 96);
+ background-image: initial;
+ background-repeat: initial;
+ background-size: initial;
+ animation: initial;
+ will-change: initial;
+
+ color: rgb(235, 235, 235);
+}
+
+section .body {
+ margin-left: 0;
+ max-width: initial;
+ transform: none;
+}
+
+h1 {
+ font-size: 3em;
+ margin: 1.5em 0 .5em;
+ text-align: center;
+}
+
+button {
+ transform: none !important;
+ min-width: initial;
+ transition: none;
+ animation: none;
+ will-change: initial;
+
+ display: block;
+ font-size: 1.5em;
+ border: 2px solid rgb(235, 235, 235);
+ color: rgb(235, 235, 235);
+ background: transparent;
+ border-radius: 10px;
+ padding: .5em 2em;
+}
+
+button:hover {
+ background-color: rgba(255, 255, 255, .1);
+ cursor: pointer;
+}
+
+button:active {
+ color: inherit;
+ background-color: rgba(255, 255, 255, .2);
+}
+
+button:disabled {
+ border-color: rgba(235, 235, 235, .5);
+ color: rgba(235, 235, 235, .5);
+}
+
+@media screen and (max-device-width: 414px),
+ screen and (max-device-height: 414px) and (orientation: landscape) {
+ h1 {
+ font-size: 2.5em;
+ }
+
+ section {
+ box-sizing: border-box;
+ width: 100%;
+ height: 100%;
+ padding: 0 5px;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+/* Tree */
+/* -------------------------------------------------------------------------- */
+
+.tree {
+ padding: 0;
+ list-style-type: none;
+}
+
+.tree .expand-button {
+ position: absolute;
+ clip: rect(0, 0, 0, 0);
+}
+
+.tree .expand-button ~ ul {
+ display: none;
+}
+
+.tree .expand-button:checked ~ ul {
+ display: block;
+}
+
+.tree ul {
+ list-style-type:none;
+}
+
+.tree li {
+ position: relative;
+ padding: 0 0 1em 1em;
+}
+
+.tree ul li {
+ list-style:none;
+ padding: 1em 0 0 0em;
+}
+
+.tree > li:last-child {
+ padding-bottom: 0;
+}
+
+.tree-label {
+ position: relative;
+ display: inline-block;
+}
+
+label.tree-label {
+ cursor: pointer;
+}
+
+.tree > li > label.tree-label:before {
+ position: relative;
+ z-index: 1;
+ float: left;
+ margin: 0 0 0 -2em;
+ width: 1em;
+ height: 1em;
+ content: '\25BA';
+ text-align: center;
+ line-height: 2.5em;
+ font-size: .5em;
+}
+
+.tree > li > :checked ~ label.tree-label:before {
+ content: '\25BC';
+}
+
+.tree .link {
+ cursor: pointer;
+ color: #999;
+ font-style: italic;
+ margin-left: 2em;
+}
+
+@media screen and (max-device-width: 414px),
+ screen and (max-device-height: 414px) and (orientation: landscape) {
+ .tree {
+ padding-left: 1em;
+ }
+ .tree > li > label.tree-label:before {
+ font-size: 1em;
+ margin-left: -1.75em;
+ line-height: 1em;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+/* Intro Section */
+/* -------------------------------------------------------------------------- */
+
+#intro {
+ padding: 0;
+ opacity: initial;
+ transition: none;
+}
+
+#intro .body > p {
+ padding: 1em 0;
+ margin: 0 auto;
+ text-align: center;
+}
+
+#intro .start-benchmark {
+ padding: 10vh 0;
+ text-align: center;
+}
+
+#intro .start-benchmark p {
+ color: hsl(11, 72%, 50%);
+ margin-bottom: 1em;
+ -apple-trailing-word: -apple-partially-balanced;
+}
+
+#intro .start-benchmark button {
+ margin: 0 auto;
+}
+
+
+@media screen and (max-device-width: 414px),
+ screen and (max-device-height: 414px) and (orientation: landscape) {
+ #intro.selected {
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ flex-flow: column;
+ }
+
+ #intro p {
+ padding-left: 20px;
+ padding-right: 20px;
+ font-size: 1.5em;
+ }
+}
+
+#intro h2 {
+ font-size: 1.2em;
+}
+
+#intro .body > div:first-of-type {
+ width: 100%;
+ margin: 2em 0 0;
+ flex-direction: row;
+ display: flex;
+ align-content: flex-start;
+}
+
+#suites {
+ padding-left: 15vw;
+ padding-right: 3em;
+ flex: 1 1 30%;
+}
+
+#options {
+ flex: 10 1 auto;
+}
+
+#intro input[type="number"] {
+ width: 50px;
+}
+
+#suites input[type="number"] {
+ display: none;
+ float: right;
+}
+
+#suites input[type="number"].selected {
+ display: inline;
+ margin: 0;
+}
+
+#suites ul ul {
+ font-size: .8em;
+ margin: 0;
+ padding: 0 0 0 1em;
+}
+
+#suites > div {
+ margin: 3em 0;
+}
+
+#drop-target {
+ font-size: 1em;
+ border-radius: 10px;
+ padding: .5em 2em;
+ border: 2px solid rgb(235, 235, 235);
+ color: rgb(235, 235, 235);
+}
+
+#drop-target:hover {
+ background-color: rgba(255, 255, 255, .1);
+ cursor: pointer;
+}
+
+#options ul {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+#options h3 {
+ font-size: 1em;
+ font-weight: inherit;
+ margin: 0 0 .3em 0;
+ padding: 0;
+}
+
+#options > form > ul > li {
+ padding: 0 0 1em 0;
+}
+
+#options ul ul {
+ padding: 0;
+}
+
+#options li {
+ padding: .1em 0;
+}
+
+#intro > p {
+ padding: 0 5px 1em;
+ font-size: 1em;
+}
+
+#intro .start-benchmark {
+ padding: 0 0 10vh;
+ margin-top: 0;
+}
+
+#intro .start-benchmark p {
+ color: hsl(11, 100%, 66%);
+}
+
+@media screen and (max-device-width: 414px),
+ screen and (max-device-height: 414px) and (orientation: landscape) {
+ #intro .body > div:first-of-type {
+ flex-direction: column;
+ }
+
+ #suites,
+ #options {
+ padding: 0 5px;
+ margin: 0;
+ flex: 0 0 auto;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+/* Running Section */
+/* -------------------------------------------------------------------------- */
+
+#running-test {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+#progress {
+ display: none;
+}
+
+.display-progress-bar #progress {
+ display: block;
+ position: fixed;
+ top: 0;
+ left: 0;
+ height: 6px;
+ width: 100%;
+ background-color: rgb(128, 128, 128);
+}
+
+.display-progress-bar #progress-completed {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 6px;
+ width: 0;
+ background-color: rgb(235, 96, 32);
+}
+
+body.showing-test-container.tiles-big {
+ overflow: hidden;
+}
+
+body.showing-test-container.tiles-classic {
+ width: 3000px;
+ height: 3000px;
+ overflow: scroll;
+}
+
+/* -------------------------------------------------------------------------- */
+/* Results Section */
+/* -------------------------------------------------------------------------- */
+
+#results {
+ text-align: center;
+}
+
+#results h1, #test-graph h1 {
+ font-size: 2em;
+}
+
+#results button.small-button {
+ border: 1px solid rgba(235, 235, 235, .9);
+ color: rgba(235, 235, 235, .9);
+ border-radius: 2px;
+ padding: 1px 4px;
+ margin: 0 0 0 1em;
+ font-size: 9px;
+}
+
+#results button.small-button:active {
+ background-color: rgba(235, 235, 235, .2);
+ color: inherit;
+}
+
+#results .score,
+#test-graph .score {
+ font-size: 3em;
+ font-weight: bold;
+ margin: 0;
+}
+
+#results .confidence,
+#test-graph .confidence {
+ margin-top: 0;
+ margin-bottom: 1em;
+ font-size: 1.5em;
+ font-weight: 400;
+ text-indent: inherit;
+ color: inherit;
+}
+
+#results-tables {
+ direction: rtl;
+
+ display: flex;
+
+ align-items: center;
+ justify-content: center;
+
+ margin: 3em 0;
+}
+
+#results .table-container > div {
+ margin-left: 0;
+}
+
+#results #results-score {
+ float: initial;
+}
+
+#results #results-header {
+ width: initial;
+ position: initial;
+}
+
+#results table {
+ direction: ltr;
+ min-width: initial;
+}
+
+#results table td.suites-separator {
+ padding: .5em 0;
+}
+
+#results table tr:nth-child(even) {
+ background-color: transparent;
+}
+
+#results th {
+ padding: .5em 0;
+}
+
+#results tr td {
+ padding: .25em 0;
+}
+
+#results-header td, #results-header th {
+ text-align: left;
+}
+#results-header tr td {
+ padding-right: 1em;
+}
+#results-score td, #results-score th {
+ text-align: right;
+}
+#results .body > button {
+ margin: 1.5em auto .5em;
+}
+#results footer {
+ padding-bottom: 10vh;
+}
+
+@media screen and (max-device-width: 414px),
+ screen and (max-device-height: 414px) and (orientation: landscape) {
+ #results.selected {
+ padding: 0 20px;
+ }
+}
+
+#overlay {
+ background: rgba(0, 0, 10, .8);
+}
+
+@supports (-webkit-backdrop-filter: blur(10px)) {
+ #overlay {
+ background: rgba(0, 0, 10, .4);
+ }
+}
+
+#overlay > div div {
+ border: 1px solid rgb(241, 241, 241);
+}
+
+#overlay button {
+ margin: 2em auto;
+ border-color: rgb(241, 241, 241);
+ color: rgb(241, 241, 241);
+}
+
+#overlay button:hover {
+ background-color: rgba(255, 255, 255, .1);
+}
+
+#overlay button:active {
+ background-color: rgba(255, 255, 255, .2);
+}
+
+#results-data .average {
+ padding-left: 1em;
+ text-align: right;
+}
+
+#results-data .stdev {
+ text-align: left;
+ padding-left: .25em;
+}
+
+#results-data .left {
+ text-align: left;
+}
+
+#results-data .right {
+ text-align: right;
+}
+
+#results-data .pad-left {
+ padding-left: 1em;
+}
+
+#results-data .pad-right {
+ padding-right: .25em;
+}
+
+#results-data .small {
+ font-size: .8em;
+}
+
+#results-tables td.noisy-results {
+ color: rgb(255, 104, 104);
+}
+
+#results-tables div {
+ direction: ltr;
+ display: flex;
+ flex-direction: row;
+}
+
+#test-graph {
+ flex: 1 0 calc(100% - 40px);
+}
+
+#test-graph h1 {
+ margin-bottom: 0;
+}
+
+#test-graph header {
+ position: relative;
+ text-align:center;
+}
+
+#test-graph header button {
+ position: absolute;
+ top: 0;
+ left: 0;
+ border-width: 1px;
+ font-size: 1em;
+ padding: .5em 1em;
+}
+
+#test-graph .score, #test-graph .confidence {
+ margin: 0;
+}
+
+#test-graph nav {
+ position: absolute;
+ top: 1.5em;
+ right: 0;
+ font-size: .7em;
+ width: 28em;
+}
+
+#test-graph nav ul {
+ margin: 0 30px 1em 0;
+ padding: 0;
+ list-style: none;
+}
+
+#test-graph nav li {
+ padding: .1em 0;
+}
+
+#test-graph nav li > span {
+ float: right;
+}
+
+#test-graph nav.hide-data span {
+ display: none;
+}
+
+/* -------------------------------------------------------------------------- */
+/* Graph Section */
+/* -------------------------------------------------------------------------- */
+
+#test-graph-data {
+ z-index: 1;
+ font: 10px sans-serif;
+ color: rgb(235, 235, 235);
+}
+
+#test-graph-data > svg {
+ fill: none;
+ overflow: visible;
+}
+
+.axis path,
+.axis line {
+ fill: none;
+ stroke: #999999;
+ shape-rendering: crispEdges;
+}
+
+.axis text {
+ fill: #999;
+}
+
+.yLeft.axis text {
+ fill: #7add49;
+}
+.yLeft.axis path,
+.yLeft.axis line {
+ stroke: #7add49;
+}
+.yRight.axis text {
+ fill: #fa4925;
+}
+.yRight.axis path,
+.yRight.axis line {
+ stroke: #fa4925;
+}
+
+.axis.complexity .tick line {
+ stroke: rgba(200, 200, 200, .6);
+ stroke-width: 2px;
+}
+
+.axis.complexity .domain,
+.axis.complexity text {
+ stroke: transparent;
+ fill: transparent;
+}
+
+.marker line {
+ stroke: #5493D6;
+}
+
+.marker text {
+ fill: #999;
+}
+
+.mean.complexity line {
+ stroke: hsla(100, 69%, 58%, .8);
+ stroke-width: 2px;
+}
+
+.mean.complexity polygon {
+ fill: hsla(100, 69%, 58%, .05);
+}
+
+.target-fps {
+ stroke: rgba(250, 73, 37, .4);
+ stroke-width: 1px;
+ stroke-dasharray: 10, 10;
+}
+
+.mean.fps line {
+ stroke: hsla(10, 96%, 56%, .8);
+ stroke-width: 2px;
+}
+
+.mean.fps polygon {
+ fill: hsla(10, 96%, 56%, .1);
+}
+
+#regressions line {
+ stroke: rgba(200, 200, 200, .8);
+ stroke-width: 2px;
+}
+
+#regressions circle {
+ fill: rgba(200, 200, 200, .8);
+}
+
+.cursor line {
+ stroke: rgb(250, 250, 250);
+ stroke-width: 1px;
+}
+
+.cursor circle,
+.cursor text {
+ fill: rgb(250, 250, 250);
+}
+
+#complexity path {
+ stroke: rgba(122, 221, 73, .7);
+ stroke-width: 2px;
+}
+
+#complexity circle {
+ fill: rgb(122, 221, 73);
+}
+
+#filteredFPS path {
+ stroke: hsla(30, 96%, 56%, .7);
+ stroke-width: 1px;
+}
+
+#filteredFPS circle {
+ fill: hsl(30, 96%, 56%);
+}
+
+#rawFPS path {
+ stroke: rgba(250, 73, 37, .7);
+ stroke-width: 1px;
+}
+
+#rawFPS circle {
+ fill: rgb(250, 73, 37);
+}
+
+#complexity-graph .regression line {
+ stroke: rgba(253, 253, 253, .8);
+ stroke-width: 2px;
+}
+
+#complexity-graph .regression circle {
+ fill: rgba(253, 253, 253, .8);
+}
+
+#complexity-graph .regression polygon {
+ fill: rgba(253, 253, 253, .05);
+}
+
+#complexity-graph .raw.series line {
+ stroke: hsla(30, 96%, 56%, .3);
+ stroke-width: 1px;
+}
+
+#complexity-graph .raw.regression line {
+ stroke: rgba(30, 96%, 86%, .6);
+}
+
+#complexity-graph .raw.regression polygon {
+ stroke: rgba(30, 96%, 86%, .05);
+}
+
+#complexity-graph .average.series circle {
+ fill: hsl(170, 96%, 56%);
+}
+
+#complexity-graph .average.series line {
+ stroke: hsla(170, 96%, 56%, .2);
+ stroke-width: 2px;
+}
+
+#complexity-graph .bootstrap .bar {
+ fill: hsla(260, 56%, 66%, .4);
+}
+
+#complexity-graph .bootstrap .median line {
+ stroke: hsla(300, 56%, 66%, .8);
+ stroke-width: 2px;
+}
+
+#complexity-graph .bootstrap .median circle {
+ fill: hsla(300, 56%, 66%, .8);
+}
+
+#complexity-graph .bootstrap .median polygon {
+ fill: hsla(300, 56%, 66%, .05);
+}
diff --git a/third_party/webkit/PerformanceTests/MotionMark/resources/debug-runner/animometer.js b/third_party/webkit/PerformanceTests/MotionMark/resources/debug-runner/animometer.js
new file mode 100644
index 0000000000..072cdcc762
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/resources/debug-runner/animometer.js
@@ -0,0 +1,703 @@
+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)) + "%";
+ },
+
+ incrementRange: function()
+ {
+ ++this._currentRange;
+ this._updateElement();
+ }
+});
+
+DeveloperResultsTable = Utilities.createSubclass(ResultsTable,
+ function(element, headers)
+ {
+ ResultsTable.call(this, element, headers);
+ }, {
+
+ _addGraphButton: function(td, testName, testResult, testData)
+ {
+ var button = Utilities.createElement("button", { class: "small-button" }, td);
+ button.textContent = Strings.text.graph + "…";
+ button.testName = testName;
+ button.testResult = testResult;
+ button.testData = testData;
+
+ button.addEventListener("click", function(e) {
+ benchmarkController.showTestGraph(e.target.testName, e.target.testResult, e.target.testData);
+ });
+ },
+
+ _isNoisyMeasurement: function(jsonExperiment, data, measurement, options)
+ {
+ const percentThreshold = 10;
+ const averageThreshold = 2;
+
+ if (measurement == Strings.json.measurements.percent)
+ return data[Strings.json.measurements.percent] >= percentThreshold;
+
+ if (jsonExperiment == Strings.json.frameLength && measurement == Strings.json.measurements.average)
+ return Math.abs(data[Strings.json.measurements.average] - options["frame-rate"]) >= averageThreshold;
+
+ return false;
+ },
+
+ _addTest: function(testName, testResult, options, testData)
+ {
+ var row = Utilities.createElement("tr", {}, this.element);
+
+ var isNoisy = false;
+ [Strings.json.complexity, Strings.json.frameLength].forEach(function (experiment) {
+ var data = testResult[experiment];
+ for (var measurement in data) {
+ if (this._isNoisyMeasurement(experiment, data, measurement, options))
+ isNoisy = true;
+ }
+ }, this);
+
+ this._flattenedHeaders.forEach(function (header) {
+ var className = "";
+ if (header.className) {
+ if (typeof header.className == "function")
+ className = header.className(testResult, options);
+ else
+ className = header.className;
+ }
+
+ if (header.text == Strings.text.testName) {
+ if (isNoisy)
+ className += " noisy-results";
+ var td = Utilities.createElement("td", { class: className }, row);
+ td.textContent = testName;
+ return;
+ }
+
+ var td = Utilities.createElement("td", { class: className }, row);
+ if (header.title == Strings.text.graph) {
+ this._addGraphButton(td, testName, testResult, testData);
+ } else if (!("text" in header)) {
+ td.textContent = testResult[header.title];
+ } else if (typeof header.text == "string") {
+ var data = testResult[header.text];
+ if (typeof data == "number")
+ data = data.toFixed(2);
+ td.textContent = data;
+ } else
+ td.textContent = header.text(testResult);
+ }, this);
+ }
+});
+
+Utilities.extendObject(window.benchmarkRunnerClient, {
+ testsCount: null,
+ progressBar: null,
+
+ initialize: function(suites, options)
+ {
+ this.testsCount = this.iterationCount * suites.reduce(function (count, suite) { return count + suite.tests.length; }, 0);
+ this.options = options;
+ },
+
+ willStartFirstIteration: function()
+ {
+ this.results = new ResultsDashboard(this.options);
+ this.progressBar = new ProgressBar(document.getElementById("progress-completed"), this.testsCount);
+ },
+
+ didRunTest: function(testData)
+ {
+ this.progressBar.incrementRange();
+ this.results.calculateScore(testData);
+ }
+});
+
+Utilities.extendObject(window.sectionsManager, {
+ setSectionHeader: function(sectionIdentifier, title)
+ {
+ document.querySelector("#" + sectionIdentifier + " h1").textContent = title;
+ },
+
+ populateTable: function(tableIdentifier, headers, dashboard)
+ {
+ var table = new DeveloperResultsTable(document.getElementById(tableIdentifier), headers);
+ table.showIterations(dashboard);
+ }
+});
+
+window.optionsManager =
+{
+ valueForOption: function(name)
+ {
+ var formElement = document.forms["benchmark-options"].elements[name];
+ if (formElement.type == "checkbox")
+ return formElement.checked;
+ else if (formElement.constructor === HTMLCollection) {
+ for (var i = 0; i < formElement.length; ++i) {
+ var radio = formElement[i];
+ if (radio.checked)
+ return formElement.value;
+ }
+ return null;
+ }
+ return formElement.value;
+ },
+
+ updateUIFromLocalStorage: function()
+ {
+ var formElements = document.forms["benchmark-options"].elements;
+
+ for (var i = 0; i < formElements.length; ++i) {
+ var formElement = formElements[i];
+ var name = formElement.id || formElement.name;
+ var type = formElement.type;
+
+ var value = localStorage.getItem(name);
+ if (value === null)
+ continue;
+
+ if (type == "number")
+ formElements[name].value = +value;
+ else if (type == "checkbox")
+ formElements[name].checked = value == "true";
+ else if (type == "radio")
+ formElements[name].value = value;
+ }
+ },
+
+ updateLocalStorageFromUI: function()
+ {
+ var formElements = document.forms["benchmark-options"].elements;
+ var options = {};
+
+ for (var i = 0; i < formElements.length; ++i) {
+ var formElement = formElements[i];
+ var name = formElement.id || formElement.name;
+ var type = formElement.type;
+
+ if (type == "number")
+ options[name] = +formElement.value;
+ else if (type == "checkbox")
+ options[name] = formElement.checked;
+ else if (type == "radio") {
+ var radios = formElements[name];
+ if (radios.constructor === HTMLCollection) {
+ for (var j = 0; j < radios.length; ++j) {
+ var radio = radios[j];
+ if (radio.checked) {
+ options[name] = radio.value;
+ break;
+ }
+ }
+ } else
+ options[name] = formElements[name].value;
+ }
+
+ try {
+ localStorage.setItem(name, options[name]);
+ } catch (e) {}
+ }
+
+ return options;
+ },
+
+ updateDisplay: function()
+ {
+ document.body.classList.remove("display-minimal");
+ document.body.classList.remove("display-progress-bar");
+
+ document.body.classList.add("display-" + optionsManager.valueForOption("display"));
+ },
+
+ updateTiles: function()
+ {
+ document.body.classList.remove("tiles-big");
+ document.body.classList.remove("tiles-classic");
+
+ document.body.classList.add("tiles-" + optionsManager.valueForOption("tiles"));
+ }
+};
+
+window.suitesManager =
+{
+ _treeElement: function()
+ {
+ return document.querySelector("#suites > .tree");
+ },
+
+ _suitesElements: function()
+ {
+ return document.querySelectorAll("#suites > ul > li");
+ },
+
+ _checkboxElement: function(element)
+ {
+ return element.querySelector("input[type='checkbox']:not(.expand-button)");
+ },
+
+ _editElement: function(element)
+ {
+ return element.querySelector("input[type='number']");
+ },
+
+ _editsElements: function()
+ {
+ return document.querySelectorAll("#suites input[type='number']");
+ },
+
+ _localStorageNameForTest: function(suiteName, testName)
+ {
+ return suiteName + "/" + testName;
+ },
+
+ _updateSuiteCheckboxState: function(suiteCheckbox)
+ {
+ var numberEnabledTests = 0;
+ suiteCheckbox.testsElements.forEach(function(testElement) {
+ var testCheckbox = this._checkboxElement(testElement);
+ if (testCheckbox.checked)
+ ++numberEnabledTests;
+ }, this);
+ suiteCheckbox.checked = numberEnabledTests > 0;
+ suiteCheckbox.indeterminate = numberEnabledTests > 0 && numberEnabledTests < suiteCheckbox.testsElements.length;
+ },
+
+ isAtLeastOneTestSelected: function()
+ {
+ var suitesElements = this._suitesElements();
+
+ for (var i = 0; i < suitesElements.length; ++i) {
+ var suiteElement = suitesElements[i];
+ var suiteCheckbox = this._checkboxElement(suiteElement);
+
+ if (suiteCheckbox.checked)
+ return true;
+ }
+
+ return false;
+ },
+
+ _onChangeSuiteCheckbox: function(event)
+ {
+ var selected = event.target.checked;
+ event.target.testsElements.forEach(function(testElement) {
+ var testCheckbox = this._checkboxElement(testElement);
+ testCheckbox.checked = selected;
+ }, this);
+ benchmarkController.updateStartButtonState();
+ },
+
+ _onChangeTestCheckbox: function(suiteCheckbox)
+ {
+ this._updateSuiteCheckboxState(suiteCheckbox);
+ benchmarkController.updateStartButtonState();
+ },
+
+ _createSuiteElement: function(treeElement, suite, id)
+ {
+ var suiteElement = Utilities.createElement("li", {}, treeElement);
+ var expand = Utilities.createElement("input", { type: "checkbox", class: "expand-button", id: id }, suiteElement);
+ var label = Utilities.createElement("label", { class: "tree-label", for: id }, suiteElement);
+
+ var suiteCheckbox = Utilities.createElement("input", { type: "checkbox" }, label);
+ suiteCheckbox.suite = suite;
+ suiteCheckbox.onchange = this._onChangeSuiteCheckbox.bind(this);
+ suiteCheckbox.testsElements = [];
+
+ label.appendChild(document.createTextNode(" " + suite.name));
+ return suiteElement;
+ },
+
+ _createTestElement: function(listElement, test, suiteCheckbox)
+ {
+ var testElement = Utilities.createElement("li", {}, listElement);
+ var span = Utilities.createElement("label", { class: "tree-label" }, testElement);
+
+ var testCheckbox = Utilities.createElement("input", { type: "checkbox" }, span);
+ testCheckbox.test = test;
+ testCheckbox.onchange = function(event) {
+ this._onChangeTestCheckbox(event.target.suiteCheckbox);
+ }.bind(this);
+ testCheckbox.suiteCheckbox = suiteCheckbox;
+
+ suiteCheckbox.testsElements.push(testElement);
+ span.appendChild(document.createTextNode(" " + test.name + " "));
+
+ testElement.appendChild(document.createTextNode(" "));
+ var link = Utilities.createElement("span", {}, testElement);
+ link.classList.add("link");
+ link.textContent = "link";
+ link.suiteName = Utilities.stripNonASCIICharacters(suiteCheckbox.suite.name);
+ link.testName = test.name;
+ link.onclick = function(event) {
+ var element = event.target;
+ var title = "Link to run “" + element.testName + "” with current options:";
+ var url = location.href.split(/[?#]/)[0];
+ var options = optionsManager.updateLocalStorageFromUI();
+ Utilities.extendObject(options, {
+ "suite-name": element.suiteName,
+ "test-name": Utilities.stripNonASCIICharacters(element.testName)
+ });
+ var complexity = suitesManager._editElement(element.parentNode).value;
+ if (complexity)
+ options.complexity = complexity;
+ prompt(title, url + Utilities.convertObjectToQueryString(options));
+ };
+
+ var complexity = Utilities.createElement("input", { type: "number" }, testElement);
+ complexity.relatedCheckbox = testCheckbox;
+ complexity.oninput = function(event) {
+ var relatedCheckbox = event.target.relatedCheckbox;
+ relatedCheckbox.checked = true;
+ this._onChangeTestCheckbox(relatedCheckbox.suiteCheckbox);
+ }.bind(this);
+ return testElement;
+ },
+
+ createElements: function()
+ {
+ var treeElement = this._treeElement();
+
+ Suites.forEach(function(suite, index) {
+ var suiteElement = this._createSuiteElement(treeElement, suite, "suite-" + index);
+ var listElement = Utilities.createElement("ul", {}, suiteElement);
+ var suiteCheckbox = this._checkboxElement(suiteElement);
+
+ suite.tests.forEach(function(test) {
+ this._createTestElement(listElement, test, suiteCheckbox);
+ }, this);
+ }, this);
+ },
+
+ updateEditsElementsState: function()
+ {
+ var editsElements = this._editsElements();
+ var showComplexityInputs = ["fixed", "step"].indexOf(optionsManager.valueForOption("controller")) != -1;
+
+ for (var i = 0; i < editsElements.length; ++i) {
+ var editElement = editsElements[i];
+ if (showComplexityInputs)
+ editElement.classList.add("selected");
+ else
+ editElement.classList.remove("selected");
+ }
+ },
+
+ updateUIFromLocalStorage: function()
+ {
+ var suitesElements = this._suitesElements();
+
+ for (var i = 0; i < suitesElements.length; ++i) {
+ var suiteElement = suitesElements[i];
+ var suiteCheckbox = this._checkboxElement(suiteElement);
+ var suite = suiteCheckbox.suite;
+
+ suiteCheckbox.testsElements.forEach(function(testElement) {
+ var testCheckbox = this._checkboxElement(testElement);
+ var testEdit = this._editElement(testElement);
+ var test = testCheckbox.test;
+
+ var str = localStorage.getItem(this._localStorageNameForTest(suite.name, test.name));
+ if (str === null)
+ return;
+
+ var value = JSON.parse(str);
+ testCheckbox.checked = value.checked;
+ testEdit.value = value.complexity;
+ }, this);
+
+ this._updateSuiteCheckboxState(suiteCheckbox);
+ }
+
+ benchmarkController.updateStartButtonState();
+ },
+
+ updateLocalStorageFromUI: function()
+ {
+ var suitesElements = this._suitesElements();
+ var suites = [];
+
+ for (var i = 0; i < suitesElements.length; ++i) {
+ var suiteElement = suitesElements[i];
+ var suiteCheckbox = this._checkboxElement(suiteElement);
+ var suite = suiteCheckbox.suite;
+
+ var tests = [];
+ suiteCheckbox.testsElements.forEach(function(testElement) {
+ var testCheckbox = this._checkboxElement(testElement);
+ var testEdit = this._editElement(testElement);
+ var test = testCheckbox.test;
+
+ if (testCheckbox.checked) {
+ test.complexity = testEdit.value;
+ tests.push(test);
+ }
+
+ var value = { checked: testCheckbox.checked, complexity: testEdit.value };
+ try {
+ localStorage.setItem(this._localStorageNameForTest(suite.name, test.name), JSON.stringify(value));
+ } catch (e) {}
+ }, this);
+
+ if (tests.length)
+ suites.push(new Suite(suiteCheckbox.suite.name, tests));
+ }
+
+ return suites;
+ },
+
+ suitesFromQueryString: function(suiteName, testName, oskey=null)
+ {
+ var suites = [];
+ var suiteRegExp = new RegExp(suiteName, "i");
+ var testRegExp = new RegExp(testName, "i");
+
+ for (var i = 0; i < Suites.length; ++i) {
+ var suite = Suites[i];
+ if (!Utilities.stripNonASCIICharacters(suite.name).match(suiteRegExp))
+ continue;
+
+ var test;
+ for (var j = 0; j < suite.tests.length; ++j) {
+ suiteTest = suite.tests[j];
+ // MOZILLA: Run all the tests in a given suite
+ if (typeof(testName) === "undefined") {
+ let complexity = {"HTMLsuite": {
+ "CSSbouncingcircles": {"win": 322, "linux64": 322, "osx": 218},
+ "CSSbouncingclippedrects": {"win": 520, "linux64": 520, "osx": 75},
+ "CSSbouncinggradientcircles": {"win": 402, "linux64": 402, "osx": 97},
+ "CSSbouncingblendcircles": {"win": 171, "linux64": 171, "osx": 254},
+ "CSSbouncingfiltercircles": {"win": 189, "linux64": 189, "osx": 189},
+ "CSSbouncingSVGimages": {"win": 329, "linux64": 329, "osx": 392},
+ "CSSbouncingtaggedimages": {"win": 255, "linux64": 255, "osx": 351},
+ "Leaves20": {"win": 262, "linux64": 262, "osx": 191},
+ "Focus20": {"win": 15, "linux64": 15, "osx": 18},
+ "DOMparticlesSVGmasks": {"win": 390, "linux64": 390, "osx": 54},
+ "CompositedTransforms": {"win": 400, "linux64": 400, "osx": 75}
+ }, "Animometer": {
+ "Multiply": {"win": 391, "linux64": 391, "osx": 193},
+ "CanvasArcs": {"win": 1287, "linux64": 1287, "osx": 575},
+ "Leaves": {"win": 550, "linux64": 550, "osx": 271},
+ "Paths": {"win": 4070, "linux64": 4070, "osx": 2024},
+ "CanvasLines": {"win": 4692, "linux64": 4692, "osx": 10932},
+ "Focus": {"win": 44, "linux64": 44, "osx": 32},
+ "Images": {"win": 293, "linux64": 293, "osx": 188},
+ "Design": {"win": 60, "linux64": 60, "osx": 17},
+ "Suits": {"win": 210, "linux64": 210, "osx": 145}
+ }
+ };
+ if (oskey == null) {
+ oskey = "linux64";
+ }
+ suiteTest.complexity = complexity[suiteName][Utilities.stripNonASCIICharacters(suiteTest.name)][oskey];
+ suites.push(new Suite(suiteName, [suiteTest]));
+ continue;
+ }
+
+ if (Utilities.stripNonASCIICharacters(suiteTest.name).match(testRegExp)) {
+ test = suiteTest;
+ break;
+ }
+ }
+
+ if (!test)
+ continue;
+
+ suites.push(new Suite(suiteName, [test]));
+ };
+
+ return suites;
+ },
+
+ updateLocalStorageFromJSON: function(results)
+ {
+ for (var suiteName in results[Strings.json.results.tests]) {
+ var suiteResults = results[Strings.json.results.tests][suiteName];
+ for (var testName in suiteResults) {
+ var testResults = suiteResults[testName];
+ var data = testResults[Strings.json.controller];
+ var complexity = Math.round(data[Strings.json.measurements.average]);
+
+ var value = { checked: true, complexity: complexity };
+ try {
+ localStorage.setItem(this._localStorageNameForTest(suiteName, testName), JSON.stringify(value));
+ } catch (e) {}
+ }
+ }
+ }
+}
+
+Utilities.extendObject(window.benchmarkController, {
+ initialize: function()
+ {
+ document.forms["benchmark-options"].addEventListener("change", benchmarkController.onBenchmarkOptionsChanged, true);
+ document.forms["graph-type"].addEventListener("change", benchmarkController.onGraphTypeChanged, true);
+ document.forms["time-graph-options"].addEventListener("change", benchmarkController.onTimeGraphOptionsChanged, true);
+ document.forms["complexity-graph-options"].addEventListener("change", benchmarkController.onComplexityGraphOptionsChanged, true);
+ optionsManager.updateUIFromLocalStorage();
+ optionsManager.updateDisplay();
+ optionsManager.updateTiles();
+
+ if (benchmarkController.startBenchmarkImmediatelyIfEncoded())
+ return;
+
+ benchmarkController.addOrientationListenerIfNecessary();
+ suitesManager.createElements();
+ suitesManager.updateUIFromLocalStorage();
+ suitesManager.updateEditsElementsState();
+
+ var dropTarget = document.getElementById("drop-target");
+ function stopEvent(e) {
+ e.stopPropagation();
+ e.preventDefault();
+ }
+ dropTarget.addEventListener("dragenter", stopEvent, false);
+ dropTarget.addEventListener("dragover", stopEvent, false);
+ dropTarget.addEventListener("dragleave", stopEvent, false);
+ dropTarget.addEventListener("drop", function (e) {
+ e.stopPropagation();
+ e.preventDefault();
+
+ if (!e.dataTransfer.files.length)
+ return;
+
+ var file = e.dataTransfer.files[0];
+
+ var reader = new FileReader();
+ reader.filename = file.name;
+ reader.onload = function(e) {
+ var run = JSON.parse(e.target.result);
+ if (run.debugOutput instanceof Array)
+ run = run.debugOutput[0];
+ benchmarkRunnerClient.results = new ResultsDashboard(run.options, run.data);
+ benchmarkController.showResults();
+ };
+
+ reader.readAsText(file);
+ document.title = "File: " + reader.filename;
+ }, false);
+ },
+
+ updateStartButtonState: function()
+ {
+ var startButton = document.getElementById("run-benchmark");
+ if ("isInLandscapeOrientation" in this && !this.isInLandscapeOrientation) {
+ startButton.disabled = true;
+ return;
+ }
+ startButton.disabled = !suitesManager.isAtLeastOneTestSelected();
+ },
+
+ onBenchmarkOptionsChanged: function(event)
+ {
+ switch (event.target.name) {
+ case "controller":
+ suitesManager.updateEditsElementsState();
+ break;
+ case "display":
+ optionsManager.updateDisplay();
+ break;
+ case "tiles":
+ optionsManager.updateTiles();
+ break;
+ }
+ },
+
+ startBenchmark: function()
+ {
+ benchmarkController.determineCanvasSize();
+ benchmarkController.options = optionsManager.updateLocalStorageFromUI();
+ benchmarkController.suites = suitesManager.updateLocalStorageFromUI();
+ this._startBenchmark(benchmarkController.suites, benchmarkController.options, "running-test");
+ },
+
+ startBenchmarkImmediatelyIfEncoded: function()
+ {
+ benchmarkController.options = Utilities.convertQueryStringToObject(location.search);
+ if (!benchmarkController.options)
+ return false;
+
+ this.raptor = benchmarkController.options["raptor"];
+ benchmarkController.suites = suitesManager.suitesFromQueryString(benchmarkController.options["suite-name"],
+ benchmarkController.options["test-name"],
+ benchmarkController.options["oskey"]);
+ if (!benchmarkController.suites.length)
+ return false;
+
+ setTimeout(function() {
+ this._startBenchmark(benchmarkController.suites, benchmarkController.options, "running-test");
+ }.bind(this), 0);
+ return true;
+ },
+
+ restartBenchmark: function()
+ {
+ this._startBenchmark(benchmarkController.suites, benchmarkController.options, "running-test");
+ },
+
+ showResults: function()
+ {
+ if (!this.addedKeyEvent) {
+ document.addEventListener("keypress", this.handleKeyPress, false);
+ this.addedKeyEvent = true;
+ }
+
+ var dashboard = benchmarkRunnerClient.results;
+ if (["ramp", "ramp30"].indexOf(dashboard.options["controller"]) != -1)
+ Headers.details[3].disabled = true;
+ else {
+ Headers.details[1].disabled = true;
+ Headers.details[4].disabled = true;
+ }
+
+ if (dashboard.options[Strings.json.configuration]) {
+ document.body.classList.remove("small", "medium", "large");
+ document.body.classList.add(dashboard.options[Strings.json.configuration]);
+ }
+
+ var score = dashboard.score;
+ var item = dashboard._results['iterationsResults'][0];
+ var fullNames = new Array;
+ var values = new Array;
+ for (var suite in item['testsResults']) {
+ for (var subtest in item['testsResults'][suite.toString()]) {
+ fullNames.push(suite.toString() + "-" + subtest.toString().replace(/ /g, '_'));
+ values.push(item['testsResults'][suite.toString()][subtest.toString()]['frameLength']['average']);
+ }
+ }
+ if (typeof tpRecordTime !== "undefined") {
+ tpRecordTime(values.join(','), 0, fullNames.join(','));
+ }
+ if (this.raptor) {
+ _data = ['raptor-benchmark', 'motionmark', item['testsResults']];
+ window.postMessage(_data, '*');
+ window.sessionStorage.setItem('benchmark_results', JSON.stringify(_data));
+ }
+
+ var confidence = ((dashboard.scoreLowerBound / score - 1) * 100).toFixed(2) +
+ "% / +" + ((dashboard.scoreUpperBound / score - 1) * 100).toFixed(2) + "%";
+ sectionsManager.setSectionScore("results", score.toFixed(2), confidence);
+ sectionsManager.populateTable("results-header", Headers.testName, dashboard);
+ sectionsManager.populateTable("results-score", Headers.score, dashboard);
+ sectionsManager.populateTable("results-data", Headers.details, dashboard);
+ sectionsManager.showSection("results", true);
+
+ suitesManager.updateLocalStorageFromJSON(dashboard.results[0]);
+ },
+
+ showTestGraph: function(testName, testResult, testData)
+ {
+ sectionsManager.setSectionHeader("test-graph", testName);
+ sectionsManager.showSection("test-graph", true);
+ this.updateGraphData(testResult, testData, benchmarkRunnerClient.results.options);
+ }
+});
diff --git a/third_party/webkit/PerformanceTests/MotionMark/resources/debug-runner/d3.min.js b/third_party/webkit/PerformanceTests/MotionMark/resources/debug-runner/d3.min.js
new file mode 100644
index 0000000000..1a7ae90342
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/resources/debug-runner/d3.min.js
@@ -0,0 +1,5 @@
+!function(){function n(n,t){return t>n?-1:n>t?1:n>=t?0:0/0}function t(n){return null!=n&&!isNaN(n)}function e(n){return{left:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n(t[i],e)<0?r=i+1:u=i}return r},right:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n(t[i],e)>0?u=i:r=i+1}return r}}}function r(n){return n.length}function u(n){for(var t=1;n*t%1;)t*=10;return t}function i(n,t){try{for(var e in t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}catch(r){n.prototype=t}}function o(){}function a(n){return ia+n in this}function c(n){return n=ia+n,n in this&&delete this[n]}function s(){var n=[];return this.forEach(function(t){n.push(t)}),n}function l(){var n=0;for(var t in this)t.charCodeAt(0)===oa&&++n;return n}function f(){for(var n in this)if(n.charCodeAt(0)===oa)return!1;return!0}function h(){}function g(n,t,e){return function(){var r=e.apply(t,arguments);return r===t?n:r}}function p(n,t){if(t in n)return t;t=t.charAt(0).toUpperCase()+t.substring(1);for(var e=0,r=aa.length;r>e;++e){var u=aa[e]+t;if(u in n)return u}}function v(){}function d(){}function m(n){function t(){for(var t,r=e,u=-1,i=r.length;++u<i;)(t=r[u].on)&&t.apply(this,arguments);return n}var e=[],r=new o;return t.on=function(t,u){var i,o=r.get(t);return arguments.length<2?o&&o.on:(o&&(o.on=null,e=e.slice(0,i=e.indexOf(o)).concat(e.slice(i+1)),r.remove(t)),u&&e.push(r.set(t,{on:u})),n)},t}function y(){Zo.event.preventDefault()}function x(){for(var n,t=Zo.event;n=t.sourceEvent;)t=n;return t}function M(n){for(var t=new d,e=0,r=arguments.length;++e<r;)t[arguments[e]]=m(t);return t.of=function(e,r){return function(u){try{var i=u.sourceEvent=Zo.event;u.target=n,Zo.event=u,t[u.type].apply(e,r)}finally{Zo.event=i}}},t}function _(n){return sa(n,pa),n}function b(n){return"function"==typeof n?n:function(){return la(n,this)}}function w(n){return"function"==typeof n?n:function(){return fa(n,this)}}function S(n,t){function e(){this.removeAttribute(n)}function r(){this.removeAttributeNS(n.space,n.local)}function u(){this.setAttribute(n,t)}function i(){this.setAttributeNS(n.space,n.local,t)}function o(){var e=t.apply(this,arguments);null==e?this.removeAttribute(n):this.setAttribute(n,e)}function a(){var e=t.apply(this,arguments);null==e?this.removeAttributeNS(n.space,n.local):this.setAttributeNS(n.space,n.local,e)}return n=Zo.ns.qualify(n),null==t?n.local?r:e:"function"==typeof t?n.local?a:o:n.local?i:u}function k(n){return n.trim().replace(/\s+/g," ")}function E(n){return new RegExp("(?:^|\\s+)"+Zo.requote(n)+"(?:\\s+|$)","g")}function A(n){return(n+"").trim().split(/^|\s+/)}function C(n,t){function e(){for(var e=-1;++e<u;)n[e](this,t)}function r(){for(var e=-1,r=t.apply(this,arguments);++e<u;)n[e](this,r)}n=A(n).map(N);var u=n.length;return"function"==typeof t?r:e}function N(n){var t=E(n);return function(e,r){if(u=e.classList)return r?u.add(n):u.remove(n);var u=e.getAttribute("class")||"";r?(t.lastIndex=0,t.test(u)||e.setAttribute("class",k(u+" "+n))):e.setAttribute("class",k(u.replace(t," ")))}}function z(n,t,e){function r(){this.style.removeProperty(n)}function u(){this.style.setProperty(n,t,e)}function i(){var r=t.apply(this,arguments);null==r?this.style.removeProperty(n):this.style.setProperty(n,r,e)}return null==t?r:"function"==typeof t?i:u}function L(n,t){function e(){delete this[n]}function r(){this[n]=t}function u(){var e=t.apply(this,arguments);null==e?delete this[n]:this[n]=e}return null==t?e:"function"==typeof t?u:r}function T(n){return"function"==typeof n?n:(n=Zo.ns.qualify(n)).local?function(){return this.ownerDocument.createElementNS(n.space,n.local)}:function(){return this.ownerDocument.createElementNS(this.namespaceURI,n)}}function q(n){return{__data__:n}}function R(n){return function(){return ga(this,n)}}function D(t){return arguments.length||(t=n),function(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}}function P(n,t){for(var e=0,r=n.length;r>e;e++)for(var u,i=n[e],o=0,a=i.length;a>o;o++)(u=i[o])&&t(u,o,e);return n}function U(n){return sa(n,da),n}function j(n){var t,e;return function(r,u,i){var o,a=n[i].update,c=a.length;for(i!=e&&(e=i,t=0),u>=t&&(t=u+1);!(o=a[t])&&++t<c;);return o}}function H(){var n=this.__transition__;n&&++n.active}function F(n,t,e){function r(){var t=this[o];t&&(this.removeEventListener(n,t,t.$),delete this[o])}function u(){var u=c(t,Xo(arguments));r.call(this),this.addEventListener(n,this[o]=u,u.$=e),u._=t}function i(){var t,e=new RegExp("^__on([^.]+)"+Zo.requote(n)+"$");for(var r in this)if(t=r.match(e)){var u=this[r];this.removeEventListener(t[1],u,u.$),delete this[r]}}var o="__on"+n,a=n.indexOf("."),c=O;a>0&&(n=n.substring(0,a));var s=ya.get(n);return s&&(n=s,c=Y),a?t?u:r:t?v:i}function O(n,t){return function(e){var r=Zo.event;Zo.event=e,t[0]=this.__data__;try{n.apply(this,t)}finally{Zo.event=r}}}function Y(n,t){var e=O(n,t);return function(n){var t=this,r=n.relatedTarget;r&&(r===t||8&r.compareDocumentPosition(t))||e.call(t,n)}}function I(){var n=".dragsuppress-"+ ++Ma,t="click"+n,e=Zo.select(Wo).on("touchmove"+n,y).on("dragstart"+n,y).on("selectstart"+n,y);if(xa){var r=Bo.style,u=r[xa];r[xa]="none"}return function(i){function o(){e.on(t,null)}e.on(n,null),xa&&(r[xa]=u),i&&(e.on(t,function(){y(),o()},!0),setTimeout(o,0))}}function Z(n,t){t.changedTouches&&(t=t.changedTouches[0]);var e=n.ownerSVGElement||n;if(e.createSVGPoint){var r=e.createSVGPoint();if(0>_a&&(Wo.scrollX||Wo.scrollY)){e=Zo.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var u=e[0][0].getScreenCTM();_a=!(u.f||u.e),e.remove()}return _a?(r.x=t.pageX,r.y=t.pageY):(r.x=t.clientX,r.y=t.clientY),r=r.matrixTransform(n.getScreenCTM().inverse()),[r.x,r.y]}var i=n.getBoundingClientRect();return[t.clientX-i.left-n.clientLeft,t.clientY-i.top-n.clientTop]}function V(){return Zo.event.changedTouches[0].identifier}function X(){return Zo.event.target}function $(){return Wo}function B(n){return n>0?1:0>n?-1:0}function W(n,t,e){return(t[0]-n[0])*(e[1]-n[1])-(t[1]-n[1])*(e[0]-n[0])}function J(n){return n>1?0:-1>n?ba:Math.acos(n)}function G(n){return n>1?Sa:-1>n?-Sa:Math.asin(n)}function K(n){return((n=Math.exp(n))-1/n)/2}function Q(n){return((n=Math.exp(n))+1/n)/2}function nt(n){return((n=Math.exp(2*n))-1)/(n+1)}function tt(n){return(n=Math.sin(n/2))*n}function et(){}function rt(n,t,e){return this instanceof rt?(this.h=+n,this.s=+t,void(this.l=+e)):arguments.length<2?n instanceof rt?new rt(n.h,n.s,n.l):mt(""+n,yt,rt):new rt(n,t,e)}function ut(n,t,e){function r(n){return n>360?n-=360:0>n&&(n+=360),60>n?i+(o-i)*n/60:180>n?o:240>n?i+(o-i)*(240-n)/60:i}function u(n){return Math.round(255*r(n))}var i,o;return n=isNaN(n)?0:(n%=360)<0?n+360:n,t=isNaN(t)?0:0>t?0:t>1?1:t,e=0>e?0:e>1?1:e,o=.5>=e?e*(1+t):e+t-e*t,i=2*e-o,new gt(u(n+120),u(n),u(n-120))}function it(n,t,e){return this instanceof it?(this.h=+n,this.c=+t,void(this.l=+e)):arguments.length<2?n instanceof it?new it(n.h,n.c,n.l):n instanceof at?st(n.l,n.a,n.b):st((n=xt((n=Zo.rgb(n)).r,n.g,n.b)).l,n.a,n.b):new it(n,t,e)}function ot(n,t,e){return isNaN(n)&&(n=0),isNaN(t)&&(t=0),new at(e,Math.cos(n*=Aa)*t,Math.sin(n)*t)}function at(n,t,e){return this instanceof at?(this.l=+n,this.a=+t,void(this.b=+e)):arguments.length<2?n instanceof at?new at(n.l,n.a,n.b):n instanceof it?ot(n.l,n.c,n.h):xt((n=gt(n)).r,n.g,n.b):new at(n,t,e)}function ct(n,t,e){var r=(n+16)/116,u=r+t/500,i=r-e/200;return u=lt(u)*ja,r=lt(r)*Ha,i=lt(i)*Fa,new gt(ht(3.2404542*u-1.5371385*r-.4985314*i),ht(-.969266*u+1.8760108*r+.041556*i),ht(.0556434*u-.2040259*r+1.0572252*i))}function st(n,t,e){return n>0?new it(Math.atan2(e,t)*Ca,Math.sqrt(t*t+e*e),n):new it(0/0,0/0,n)}function lt(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}function ft(n){return n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function ht(n){return Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function gt(n,t,e){return this instanceof gt?(this.r=~~n,this.g=~~t,void(this.b=~~e)):arguments.length<2?n instanceof gt?new gt(n.r,n.g,n.b):mt(""+n,gt,ut):new gt(n,t,e)}function pt(n){return new gt(n>>16,255&n>>8,255&n)}function vt(n){return pt(n)+""}function dt(n){return 16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function mt(n,t,e){var r,u,i,o=0,a=0,c=0;if(r=/([a-z]+)\((.*)\)/i.exec(n))switch(u=r[2].split(","),r[1]){case"hsl":return e(parseFloat(u[0]),parseFloat(u[1])/100,parseFloat(u[2])/100);case"rgb":return t(_t(u[0]),_t(u[1]),_t(u[2]))}return(i=Ia.get(n))?t(i.r,i.g,i.b):(null==n||"#"!==n.charAt(0)||isNaN(i=parseInt(n.substring(1),16))||(4===n.length?(o=(3840&i)>>4,o=o>>4|o,a=240&i,a=a>>4|a,c=15&i,c=c<<4|c):7===n.length&&(o=(16711680&i)>>16,a=(65280&i)>>8,c=255&i)),t(o,a,c))}function yt(n,t,e){var r,u,i=Math.min(n/=255,t/=255,e/=255),o=Math.max(n,t,e),a=o-i,c=(o+i)/2;return a?(u=.5>c?a/(o+i):a/(2-o-i),r=n==o?(t-e)/a+(e>t?6:0):t==o?(e-n)/a+2:(n-t)/a+4,r*=60):(r=0/0,u=c>0&&1>c?0:r),new rt(r,u,c)}function xt(n,t,e){n=Mt(n),t=Mt(t),e=Mt(e);var r=ft((.4124564*n+.3575761*t+.1804375*e)/ja),u=ft((.2126729*n+.7151522*t+.072175*e)/Ha),i=ft((.0193339*n+.119192*t+.9503041*e)/Fa);return at(116*u-16,500*(r-u),200*(u-i))}function Mt(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function _t(n){var t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math.round(2.55*t):t}function bt(n){return"function"==typeof n?n:function(){return n}}function wt(n){return n}function St(n){return function(t,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=null),kt(t,e,n,r)}}function kt(n,t,e,r){function u(){var n,t=c.status;if(!t&&c.responseText||t>=200&&300>t||304===t){try{n=e.call(i,c)}catch(r){return o.error.call(i,r),void 0}o.load.call(i,n)}else o.error.call(i,c)}var i={},o=Zo.dispatch("beforesend","progress","load","error"),a={},c=new XMLHttpRequest,s=null;return!Wo.XDomainRequest||"withCredentials"in c||!/^(http(s)?:)?\/\//.test(n)||(c=new XDomainRequest),"onload"in c?c.onload=c.onerror=u:c.onreadystatechange=function(){c.readyState>3&&u()},c.onprogress=function(n){var t=Zo.event;Zo.event=n;try{o.progress.call(i,c)}finally{Zo.event=t}},i.header=function(n,t){return n=(n+"").toLowerCase(),arguments.length<2?a[n]:(null==t?delete a[n]:a[n]=t+"",i)},i.mimeType=function(n){return arguments.length?(t=null==n?null:n+"",i):t},i.responseType=function(n){return arguments.length?(s=n,i):s},i.response=function(n){return e=n,i},["get","post"].forEach(function(n){i[n]=function(){return i.send.apply(i,[n].concat(Xo(arguments)))}}),i.send=function(e,r,u){if(2===arguments.length&&"function"==typeof r&&(u=r,r=null),c.open(e,n,!0),null==t||"accept"in a||(a.accept=t+",*/*"),c.setRequestHeader)for(var l in a)c.setRequestHeader(l,a[l]);return null!=t&&c.overrideMimeType&&c.overrideMimeType(t),null!=s&&(c.responseType=s),null!=u&&i.on("error",u).on("load",function(n){u(null,n)}),o.beforesend.call(i,c),c.send(null==r?null:r),i},i.abort=function(){return c.abort(),i},Zo.rebind(i,o,"on"),null==r?i:i.get(Et(r))}function Et(n){return 1===n.length?function(t,e){n(null==t?e:null)}:n}function At(){var n=Ct(),t=Nt()-n;t>24?(isFinite(t)&&(clearTimeout($a),$a=setTimeout(At,t)),Xa=0):(Xa=1,Wa(At))}function Ct(){var n=Date.now();for(Ba=Za;Ba;)n>=Ba.t&&(Ba.f=Ba.c(n-Ba.t)),Ba=Ba.n;return n}function Nt(){for(var n,t=Za,e=1/0;t;)t.f?t=n?n.n=t.n:Za=t.n:(t.t<e&&(e=t.t),t=(n=t).n);return Va=n,e}function zt(n,t){return t-(n?Math.ceil(Math.log(n)/Math.LN10):1)}function Lt(n,t){var e=Math.pow(10,3*ua(8-t));return{scale:t>8?function(n){return n/e}:function(n){return n*e},symbol:n}}function Tt(n){var t=n.decimal,e=n.thousands,r=n.grouping,u=n.currency,i=r?function(n){for(var t=n.length,u=[],i=0,o=r[0];t>0&&o>0;)u.push(n.substring(t-=o,t+o)),o=r[i=(i+1)%r.length];return u.reverse().join(e)}:wt;return function(n){var e=Ga.exec(n),r=e[1]||" ",o=e[2]||">",a=e[3]||"",c=e[4]||"",s=e[5],l=+e[6],f=e[7],h=e[8],g=e[9],p=1,v="",d="",m=!1;switch(h&&(h=+h.substring(1)),(s||"0"===r&&"="===o)&&(s=r="0",o="=",f&&(l-=Math.floor((l-1)/4))),g){case"n":f=!0,g="g";break;case"%":p=100,d="%",g="f";break;case"p":p=100,d="%",g="r";break;case"b":case"o":case"x":case"X":"#"===c&&(v="0"+g.toLowerCase());case"c":case"d":m=!0,h=0;break;case"s":p=-1,g="r"}"$"===c&&(v=u[0],d=u[1]),"r"!=g||h||(g="g"),null!=h&&("g"==g?h=Math.max(1,Math.min(21,h)):("e"==g||"f"==g)&&(h=Math.max(0,Math.min(20,h)))),g=Ka.get(g)||qt;var y=s&&f;return function(n){var e=d;if(m&&n%1)return"";var u=0>n||0===n&&0>1/n?(n=-n,"-"):a;if(0>p){var c=Zo.formatPrefix(n,h);n=c.scale(n),e=c.symbol+d}else n*=p;n=g(n,h);var x=n.lastIndexOf("."),M=0>x?n:n.substring(0,x),_=0>x?"":t+n.substring(x+1);!s&&f&&(M=i(M));var b=v.length+M.length+_.length+(y?0:u.length),w=l>b?new Array(b=l-b+1).join(r):"";return y&&(M=i(w+M)),u+=v,n=M+_,("<"===o?u+n+w:">"===o?w+u+n:"^"===o?w.substring(0,b>>=1)+u+n+w.substring(b):u+(y?n:w+n))+e}}}function qt(n){return n+""}function Rt(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function Dt(n,t,e){function r(t){var e=n(t),r=i(e,1);return r-t>t-e?e:r}function u(e){return t(e=n(new nc(e-1)),1),e}function i(n,e){return t(n=new nc(+n),e),n}function o(n,r,i){var o=u(n),a=[];if(i>1)for(;r>o;)e(o)%i||a.push(new Date(+o)),t(o,1);else for(;r>o;)a.push(new Date(+o)),t(o,1);return a}function a(n,t,e){try{nc=Rt;var r=new Rt;return r._=n,o(r,t,e)}finally{nc=Date}}n.floor=n,n.round=r,n.ceil=u,n.offset=i,n.range=o;var c=n.utc=Pt(n);return c.floor=c,c.round=Pt(r),c.ceil=Pt(u),c.offset=Pt(i),c.range=a,n}function Pt(n){return function(t,e){try{nc=Rt;var r=new Rt;return r._=t,n(r,e)._}finally{nc=Date}}}function Ut(n){function t(n){function t(t){for(var e,u,i,o=[],a=-1,c=0;++a<r;)37===n.charCodeAt(a)&&(o.push(n.substring(c,a)),null!=(u=ec[e=n.charAt(++a)])&&(e=n.charAt(++a)),(i=C[e])&&(e=i(t,null==u?"e"===e?" ":"0":u)),o.push(e),c=a+1);return o.push(n.substring(c,a)),o.join("")}var r=n.length;return t.parse=function(t){var r={y:1900,m:0,d:1,H:0,M:0,S:0,L:0,Z:null},u=e(r,n,t,0);if(u!=t.length)return null;"p"in r&&(r.H=r.H%12+12*r.p);var i=null!=r.Z&&nc!==Rt,o=new(i?Rt:nc);return"j"in r?o.setFullYear(r.y,0,r.j):"w"in r&&("W"in r||"U"in r)?(o.setFullYear(r.y,0,1),o.setFullYear(r.y,0,"W"in r?(r.w+6)%7+7*r.W-(o.getDay()+5)%7:r.w+7*r.U-(o.getDay()+6)%7)):o.setFullYear(r.y,r.m,r.d),o.setHours(r.H+Math.floor(r.Z/100),r.M+r.Z%100,r.S,r.L),i?o._:o},t.toString=function(){return n},t}function e(n,t,e,r){for(var u,i,o,a=0,c=t.length,s=e.length;c>a;){if(r>=s)return-1;if(u=t.charCodeAt(a++),37===u){if(o=t.charAt(a++),i=N[o in ec?t.charAt(a++):o],!i||(r=i(n,e,r))<0)return-1}else if(u!=e.charCodeAt(r++))return-1}return r}function r(n,t,e){b.lastIndex=0;var r=b.exec(t.substring(e));return r?(n.w=w.get(r[0].toLowerCase()),e+r[0].length):-1}function u(n,t,e){M.lastIndex=0;var r=M.exec(t.substring(e));return r?(n.w=_.get(r[0].toLowerCase()),e+r[0].length):-1}function i(n,t,e){E.lastIndex=0;var r=E.exec(t.substring(e));return r?(n.m=A.get(r[0].toLowerCase()),e+r[0].length):-1}function o(n,t,e){S.lastIndex=0;var r=S.exec(t.substring(e));return r?(n.m=k.get(r[0].toLowerCase()),e+r[0].length):-1}function a(n,t,r){return e(n,C.c.toString(),t,r)}function c(n,t,r){return e(n,C.x.toString(),t,r)}function s(n,t,r){return e(n,C.X.toString(),t,r)}function l(n,t,e){var r=x.get(t.substring(e,e+=2).toLowerCase());return null==r?-1:(n.p=r,e)}var f=n.dateTime,h=n.date,g=n.time,p=n.periods,v=n.days,d=n.shortDays,m=n.months,y=n.shortMonths;t.utc=function(n){function e(n){try{nc=Rt;var t=new nc;return t._=n,r(t)}finally{nc=Date}}var r=t(n);return e.parse=function(n){try{nc=Rt;var t=r.parse(n);return t&&t._}finally{nc=Date}},e.toString=r.toString,e},t.multi=t.utc.multi=re;var x=Zo.map(),M=Ht(v),_=Ft(v),b=Ht(d),w=Ft(d),S=Ht(m),k=Ft(m),E=Ht(y),A=Ft(y);p.forEach(function(n,t){x.set(n.toLowerCase(),t)});var C={a:function(n){return d[n.getDay()]},A:function(n){return v[n.getDay()]},b:function(n){return y[n.getMonth()]},B:function(n){return m[n.getMonth()]},c:t(f),d:function(n,t){return jt(n.getDate(),t,2)},e:function(n,t){return jt(n.getDate(),t,2)},H:function(n,t){return jt(n.getHours(),t,2)},I:function(n,t){return jt(n.getHours()%12||12,t,2)},j:function(n,t){return jt(1+Qa.dayOfYear(n),t,3)},L:function(n,t){return jt(n.getMilliseconds(),t,3)},m:function(n,t){return jt(n.getMonth()+1,t,2)},M:function(n,t){return jt(n.getMinutes(),t,2)},p:function(n){return p[+(n.getHours()>=12)]},S:function(n,t){return jt(n.getSeconds(),t,2)},U:function(n,t){return jt(Qa.sundayOfYear(n),t,2)},w:function(n){return n.getDay()},W:function(n,t){return jt(Qa.mondayOfYear(n),t,2)},x:t(h),X:t(g),y:function(n,t){return jt(n.getFullYear()%100,t,2)},Y:function(n,t){return jt(n.getFullYear()%1e4,t,4)},Z:te,"%":function(){return"%"}},N={a:r,A:u,b:i,B:o,c:a,d:Wt,e:Wt,H:Gt,I:Gt,j:Jt,L:ne,m:Bt,M:Kt,p:l,S:Qt,U:Yt,w:Ot,W:It,x:c,X:s,y:Vt,Y:Zt,Z:Xt,"%":ee};return t}function jt(n,t,e){var r=0>n?"-":"",u=(r?-n:n)+"",i=u.length;return r+(e>i?new Array(e-i+1).join(t)+u:u)}function Ht(n){return new RegExp("^(?:"+n.map(Zo.requote).join("|")+")","i")}function Ft(n){for(var t=new o,e=-1,r=n.length;++e<r;)t.set(n[e].toLowerCase(),e);return t}function Ot(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+1));return r?(n.w=+r[0],e+r[0].length):-1}function Yt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e));return r?(n.U=+r[0],e+r[0].length):-1}function It(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e));return r?(n.W=+r[0],e+r[0].length):-1}function Zt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+4));return r?(n.y=+r[0],e+r[0].length):-1}function Vt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+2));return r?(n.y=$t(+r[0]),e+r[0].length):-1}function Xt(n,t,e){return/^[+-]\d{4}$/.test(t=t.substring(e,e+5))?(n.Z=-t,e+5):-1}function $t(n){return n+(n>68?1900:2e3)}function Bt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+2));return r?(n.m=r[0]-1,e+r[0].length):-1}function Wt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+2));return r?(n.d=+r[0],e+r[0].length):-1}function Jt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+3));return r?(n.j=+r[0],e+r[0].length):-1}function Gt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+2));return r?(n.H=+r[0],e+r[0].length):-1}function Kt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+2));return r?(n.M=+r[0],e+r[0].length):-1}function Qt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+2));return r?(n.S=+r[0],e+r[0].length):-1}function ne(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+3));return r?(n.L=+r[0],e+r[0].length):-1}function te(n){var t=n.getTimezoneOffset(),e=t>0?"-":"+",r=~~(ua(t)/60),u=ua(t)%60;return e+jt(r,"0",2)+jt(u,"0",2)}function ee(n,t,e){uc.lastIndex=0;var r=uc.exec(t.substring(e,e+1));return r?e+r[0].length:-1}function re(n){for(var t=n.length,e=-1;++e<t;)n[e][0]=this(n[e][0]);return function(t){for(var e=0,r=n[e];!r[1](t);)r=n[++e];return r[0](t)}}function ue(){}function ie(n,t,e){var r=e.s=n+t,u=r-n,i=r-u;e.t=n-i+(t-u)}function oe(n,t){n&&cc.hasOwnProperty(n.type)&&cc[n.type](n,t)}function ae(n,t,e){var r,u=-1,i=n.length-e;for(t.lineStart();++u<i;)r=n[u],t.point(r[0],r[1],r[2]);t.lineEnd()}function ce(n,t){var e=-1,r=n.length;for(t.polygonStart();++e<r;)ae(n[e],t,1);t.polygonEnd()}function se(){function n(n,t){n*=Aa,t=t*Aa/2+ba/4;var e=n-r,o=e>=0?1:-1,a=o*e,c=Math.cos(t),s=Math.sin(t),l=i*s,f=u*c+l*Math.cos(a),h=l*o*Math.sin(a);lc.add(Math.atan2(h,f)),r=n,u=c,i=s}var t,e,r,u,i;fc.point=function(o,a){fc.point=n,r=(t=o)*Aa,u=Math.cos(a=(e=a)*Aa/2+ba/4),i=Math.sin(a)},fc.lineEnd=function(){n(t,e)}}function le(n){var t=n[0],e=n[1],r=Math.cos(e);return[r*Math.cos(t),r*Math.sin(t),Math.sin(e)]}function fe(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]}function he(n,t){return[n[1]*t[2]-n[2]*t[1],n[2]*t[0]-n[0]*t[2],n[0]*t[1]-n[1]*t[0]]}function ge(n,t){n[0]+=t[0],n[1]+=t[1],n[2]+=t[2]}function pe(n,t){return[n[0]*t,n[1]*t,n[2]*t]}function ve(n){var t=Math.sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);n[0]/=t,n[1]/=t,n[2]/=t}function de(n){return[Math.atan2(n[1],n[0]),G(n[2])]}function me(n,t){return ua(n[0]-t[0])<ka&&ua(n[1]-t[1])<ka}function ye(n,t){n*=Aa;var e=Math.cos(t*=Aa);xe(e*Math.cos(n),e*Math.sin(n),Math.sin(t))}function xe(n,t,e){++hc,pc+=(n-pc)/hc,vc+=(t-vc)/hc,dc+=(e-dc)/hc}function Me(){function n(n,u){n*=Aa;var i=Math.cos(u*=Aa),o=i*Math.cos(n),a=i*Math.sin(n),c=Math.sin(u),s=Math.atan2(Math.sqrt((s=e*c-r*a)*s+(s=r*o-t*c)*s+(s=t*a-e*o)*s),t*o+e*a+r*c);gc+=s,mc+=s*(t+(t=o)),yc+=s*(e+(e=a)),xc+=s*(r+(r=c)),xe(t,e,r)}var t,e,r;wc.point=function(u,i){u*=Aa;var o=Math.cos(i*=Aa);t=o*Math.cos(u),e=o*Math.sin(u),r=Math.sin(i),wc.point=n,xe(t,e,r)}}function _e(){wc.point=ye}function be(){function n(n,t){n*=Aa;var e=Math.cos(t*=Aa),o=e*Math.cos(n),a=e*Math.sin(n),c=Math.sin(t),s=u*c-i*a,l=i*o-r*c,f=r*a-u*o,h=Math.sqrt(s*s+l*l+f*f),g=r*o+u*a+i*c,p=h&&-J(g)/h,v=Math.atan2(h,g);Mc+=p*s,_c+=p*l,bc+=p*f,gc+=v,mc+=v*(r+(r=o)),yc+=v*(u+(u=a)),xc+=v*(i+(i=c)),xe(r,u,i)}var t,e,r,u,i;wc.point=function(o,a){t=o,e=a,wc.point=n,o*=Aa;var c=Math.cos(a*=Aa);r=c*Math.cos(o),u=c*Math.sin(o),i=Math.sin(a),xe(r,u,i)},wc.lineEnd=function(){n(t,e),wc.lineEnd=_e,wc.point=ye}}function we(){return!0}function Se(n,t,e,r,u){var i=[],o=[];if(n.forEach(function(n){if(!((t=n.length-1)<=0)){var t,e=n[0],r=n[t];if(me(e,r)){u.lineStart();for(var a=0;t>a;++a)u.point((e=n[a])[0],e[1]);return u.lineEnd(),void 0}var c=new Ee(e,n,null,!0),s=new Ee(e,null,c,!1);c.o=s,i.push(c),o.push(s),c=new Ee(r,n,null,!1),s=new Ee(r,null,c,!0),c.o=s,i.push(c),o.push(s)}}),o.sort(t),ke(i),ke(o),i.length){for(var a=0,c=e,s=o.length;s>a;++a)o[a].e=c=!c;for(var l,f,h=i[0];;){for(var g=h,p=!0;g.v;)if((g=g.n)===h)return;l=g.z,u.lineStart();do{if(g.v=g.o.v=!0,g.e){if(p)for(var a=0,s=l.length;s>a;++a)u.point((f=l[a])[0],f[1]);else r(g.x,g.n.x,1,u);g=g.n}else{if(p){l=g.p.z;for(var a=l.length-1;a>=0;--a)u.point((f=l[a])[0],f[1])}else r(g.x,g.p.x,-1,u);g=g.p}g=g.o,l=g.z,p=!p}while(!g.v);u.lineEnd()}}}function ke(n){if(t=n.length){for(var t,e,r=0,u=n[0];++r<t;)u.n=e=n[r],e.p=u,u=e;u.n=e=n[0],e.p=u}}function Ee(n,t,e,r){this.x=n,this.z=t,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function Ae(n,t,e,r){return function(u,i){function o(t,e){var r=u(t,e);n(t=r[0],e=r[1])&&i.point(t,e)}function a(n,t){var e=u(n,t);d.point(e[0],e[1])}function c(){y.point=a,d.lineStart()}function s(){y.point=o,d.lineEnd()}function l(n,t){v.push([n,t]);var e=u(n,t);M.point(e[0],e[1])}function f(){M.lineStart(),v=[]}function h(){l(v[0][0],v[0][1]),M.lineEnd();var n,t=M.clean(),e=x.buffer(),r=e.length;if(v.pop(),p.push(v),v=null,r)if(1&t){n=e[0];var u,r=n.length-1,o=-1;if(r>0){for(_||(i.polygonStart(),_=!0),i.lineStart();++o<r;)i.point((u=n[o])[0],u[1]);i.lineEnd()}}else r>1&&2&t&&e.push(e.pop().concat(e.shift())),g.push(e.filter(Ce))}var g,p,v,d=t(i),m=u.invert(r[0],r[1]),y={point:o,lineStart:c,lineEnd:s,polygonStart:function(){y.point=l,y.lineStart=f,y.lineEnd=h,g=[],p=[]},polygonEnd:function(){y.point=o,y.lineStart=c,y.lineEnd=s,g=Zo.merge(g);var n=Le(m,p);g.length?(_||(i.polygonStart(),_=!0),Se(g,ze,n,e,i)):n&&(_||(i.polygonStart(),_=!0),i.lineStart(),e(null,null,1,i),i.lineEnd()),_&&(i.polygonEnd(),_=!1),g=p=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}},x=Ne(),M=t(x),_=!1;return y}}function Ce(n){return n.length>1}function Ne(){var n,t=[];return{lineStart:function(){t.push(n=[])},point:function(t,e){n.push([t,e])},lineEnd:v,buffer:function(){var e=t;return t=[],n=null,e},rejoin:function(){t.length>1&&t.push(t.pop().concat(t.shift()))}}}function ze(n,t){return((n=n.x)[0]<0?n[1]-Sa-ka:Sa-n[1])-((t=t.x)[0]<0?t[1]-Sa-ka:Sa-t[1])}function Le(n,t){var e=n[0],r=n[1],u=[Math.sin(e),-Math.cos(e),0],i=0,o=0;lc.reset();for(var a=0,c=t.length;c>a;++a){var s=t[a],l=s.length;if(l)for(var f=s[0],h=f[0],g=f[1]/2+ba/4,p=Math.sin(g),v=Math.cos(g),d=1;;){d===l&&(d=0),n=s[d];var m=n[0],y=n[1]/2+ba/4,x=Math.sin(y),M=Math.cos(y),_=m-h,b=_>=0?1:-1,w=b*_,S=w>ba,k=p*x;if(lc.add(Math.atan2(k*b*Math.sin(w),v*M+k*Math.cos(w))),i+=S?_+b*wa:_,S^h>=e^m>=e){var E=he(le(f),le(n));ve(E);var A=he(u,E);ve(A);var C=(S^_>=0?-1:1)*G(A[2]);(r>C||r===C&&(E[0]||E[1]))&&(o+=S^_>=0?1:-1)}if(!d++)break;h=m,p=x,v=M,f=n}}return(-ka>i||ka>i&&0>lc)^1&o}function Te(n){var t,e=0/0,r=0/0,u=0/0;return{lineStart:function(){n.lineStart(),t=1},point:function(i,o){var a=i>0?ba:-ba,c=ua(i-e);ua(c-ba)<ka?(n.point(e,r=(r+o)/2>0?Sa:-Sa),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),n.point(i,r),t=0):u!==a&&c>=ba&&(ua(e-u)<ka&&(e-=u*ka),ua(i-a)<ka&&(i-=a*ka),r=qe(e,r,i,o),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),t=0),n.point(e=i,r=o),u=a},lineEnd:function(){n.lineEnd(),e=r=0/0},clean:function(){return 2-t}}}function qe(n,t,e,r){var u,i,o=Math.sin(n-e);return ua(o)>ka?Math.atan((Math.sin(t)*(i=Math.cos(r))*Math.sin(e)-Math.sin(r)*(u=Math.cos(t))*Math.sin(n))/(u*i*o)):(t+r)/2}function Re(n,t,e,r){var u;if(null==n)u=e*Sa,r.point(-ba,u),r.point(0,u),r.point(ba,u),r.point(ba,0),r.point(ba,-u),r.point(0,-u),r.point(-ba,-u),r.point(-ba,0),r.point(-ba,u);else if(ua(n[0]-t[0])>ka){var i=n[0]<t[0]?ba:-ba;u=e*i/2,r.point(-i,u),r.point(0,u),r.point(i,u)}else r.point(t[0],t[1])}function De(n){function t(n,t){return Math.cos(n)*Math.cos(t)>i}function e(n){var e,i,c,s,l;return{lineStart:function(){s=c=!1,l=1},point:function(f,h){var g,p=[f,h],v=t(f,h),d=o?v?0:u(f,h):v?u(f+(0>f?ba:-ba),h):0;if(!e&&(s=c=v)&&n.lineStart(),v!==c&&(g=r(e,p),(me(e,g)||me(p,g))&&(p[0]+=ka,p[1]+=ka,v=t(p[0],p[1]))),v!==c)l=0,v?(n.lineStart(),g=r(p,e),n.point(g[0],g[1])):(g=r(e,p),n.point(g[0],g[1]),n.lineEnd()),e=g;else if(a&&e&&o^v){var m;d&i||!(m=r(p,e,!0))||(l=0,o?(n.lineStart(),n.point(m[0][0],m[0][1]),n.point(m[1][0],m[1][1]),n.lineEnd()):(n.point(m[1][0],m[1][1]),n.lineEnd(),n.lineStart(),n.point(m[0][0],m[0][1])))}!v||e&&me(e,p)||n.point(p[0],p[1]),e=p,c=v,i=d},lineEnd:function(){c&&n.lineEnd(),e=null},clean:function(){return l|(s&&c)<<1}}}function r(n,t,e){var r=le(n),u=le(t),o=[1,0,0],a=he(r,u),c=fe(a,a),s=a[0],l=c-s*s;if(!l)return!e&&n;var f=i*c/l,h=-i*s/l,g=he(o,a),p=pe(o,f),v=pe(a,h);ge(p,v);var d=g,m=fe(p,d),y=fe(d,d),x=m*m-y*(fe(p,p)-1);if(!(0>x)){var M=Math.sqrt(x),_=pe(d,(-m-M)/y);if(ge(_,p),_=de(_),!e)return _;var b,w=n[0],S=t[0],k=n[1],E=t[1];w>S&&(b=w,w=S,S=b);var A=S-w,C=ua(A-ba)<ka,N=C||ka>A;if(!C&&k>E&&(b=k,k=E,E=b),N?C?k+E>0^_[1]<(ua(_[0]-w)<ka?k:E):k<=_[1]&&_[1]<=E:A>ba^(w<=_[0]&&_[0]<=S)){var z=pe(d,(-m+M)/y);return ge(z,p),[_,de(z)]}}}function u(t,e){var r=o?n:ba-n,u=0;return-r>t?u|=1:t>r&&(u|=2),-r>e?u|=4:e>r&&(u|=8),u}var i=Math.cos(n),o=i>0,a=ua(i)>ka,c=sr(n,6*Aa);return Ae(t,e,c,o?[0,-n]:[-ba,n-ba])}function Pe(n,t,e,r){return function(u){var i,o=u.a,a=u.b,c=o.x,s=o.y,l=a.x,f=a.y,h=0,g=1,p=l-c,v=f-s;if(i=n-c,p||!(i>0)){if(i/=p,0>p){if(h>i)return;g>i&&(g=i)}else if(p>0){if(i>g)return;i>h&&(h=i)}if(i=e-c,p||!(0>i)){if(i/=p,0>p){if(i>g)return;i>h&&(h=i)}else if(p>0){if(h>i)return;g>i&&(g=i)}if(i=t-s,v||!(i>0)){if(i/=v,0>v){if(h>i)return;g>i&&(g=i)}else if(v>0){if(i>g)return;i>h&&(h=i)}if(i=r-s,v||!(0>i)){if(i/=v,0>v){if(i>g)return;i>h&&(h=i)}else if(v>0){if(h>i)return;g>i&&(g=i)}return h>0&&(u.a={x:c+h*p,y:s+h*v}),1>g&&(u.b={x:c+g*p,y:s+g*v}),u}}}}}}function Ue(n,t,e,r){function u(r,u){return ua(r[0]-n)<ka?u>0?0:3:ua(r[0]-e)<ka?u>0?2:1:ua(r[1]-t)<ka?u>0?1:0:u>0?3:2}function i(n,t){return o(n.x,t.x)}function o(n,t){var e=u(n,1),r=u(t,1);return e!==r?e-r:0===e?t[1]-n[1]:1===e?n[0]-t[0]:2===e?n[1]-t[1]:t[0]-n[0]}return function(a){function c(n){for(var t=0,e=d.length,r=n[1],u=0;e>u;++u)for(var i,o=1,a=d[u],c=a.length,s=a[0];c>o;++o)i=a[o],s[1]<=r?i[1]>r&&W(s,i,n)>0&&++t:i[1]<=r&&W(s,i,n)<0&&--t,s=i;return 0!==t}function s(i,a,c,s){var l=0,f=0;if(null==i||(l=u(i,c))!==(f=u(a,c))||o(i,a)<0^c>0){do s.point(0===l||3===l?n:e,l>1?r:t);while((l=(l+c+4)%4)!==f)}else s.point(a[0],a[1])}function l(u,i){return u>=n&&e>=u&&i>=t&&r>=i}function f(n,t){l(n,t)&&a.point(n,t)}function h(){N.point=p,d&&d.push(m=[]),S=!0,w=!1,_=b=0/0}function g(){v&&(p(y,x),M&&w&&A.rejoin(),v.push(A.buffer())),N.point=f,w&&a.lineEnd()}function p(n,t){n=Math.max(-kc,Math.min(kc,n)),t=Math.max(-kc,Math.min(kc,t));var e=l(n,t);if(d&&m.push([n,t]),S)y=n,x=t,M=e,S=!1,e&&(a.lineStart(),a.point(n,t));else if(e&&w)a.point(n,t);else{var r={a:{x:_,y:b},b:{x:n,y:t}};C(r)?(w||(a.lineStart(),a.point(r.a.x,r.a.y)),a.point(r.b.x,r.b.y),e||a.lineEnd(),k=!1):e&&(a.lineStart(),a.point(n,t),k=!1)}_=n,b=t,w=e}var v,d,m,y,x,M,_,b,w,S,k,E=a,A=Ne(),C=Pe(n,t,e,r),N={point:f,lineStart:h,lineEnd:g,polygonStart:function(){a=A,v=[],d=[],k=!0},polygonEnd:function(){a=E,v=Zo.merge(v);var t=c([n,r]),e=k&&t,u=v.length;(e||u)&&(a.polygonStart(),e&&(a.lineStart(),s(null,null,1,a),a.lineEnd()),u&&Se(v,i,t,s,a),a.polygonEnd()),v=d=m=null}};return N}}function je(n,t){function e(e,r){return e=n(e,r),t(e[0],e[1])}return n.invert&&t.invert&&(e.invert=function(e,r){return e=t.invert(e,r),e&&n.invert(e[0],e[1])}),e}function He(n){var t=0,e=ba/3,r=tr(n),u=r(t,e);return u.parallels=function(n){return arguments.length?r(t=n[0]*ba/180,e=n[1]*ba/180):[180*(t/ba),180*(e/ba)]},u}function Fe(n,t){function e(n,t){var e=Math.sqrt(i-2*u*Math.sin(t))/u;return[e*Math.sin(n*=u),o-e*Math.cos(n)]}var r=Math.sin(n),u=(r+Math.sin(t))/2,i=1+r*(2*u-r),o=Math.sqrt(i)/u;return e.invert=function(n,t){var e=o-t;return[Math.atan2(n,e)/u,G((i-(n*n+e*e)*u*u)/(2*u))]},e}function Oe(){function n(n,t){Ac+=u*n-r*t,r=n,u=t}var t,e,r,u;Tc.point=function(i,o){Tc.point=n,t=r=i,e=u=o},Tc.lineEnd=function(){n(t,e)}}function Ye(n,t){Cc>n&&(Cc=n),n>zc&&(zc=n),Nc>t&&(Nc=t),t>Lc&&(Lc=t)}function Ie(){function n(n,t){o.push("M",n,",",t,i)}function t(n,t){o.push("M",n,",",t),a.point=e}function e(n,t){o.push("L",n,",",t)}function r(){a.point=n}function u(){o.push("Z")}var i=Ze(4.5),o=[],a={point:n,lineStart:function(){a.point=t},lineEnd:r,polygonStart:function(){a.lineEnd=u},polygonEnd:function(){a.lineEnd=r,a.point=n},pointRadius:function(n){return i=Ze(n),a},result:function(){if(o.length){var n=o.join("");return o=[],n}}};return a}function Ze(n){return"m0,"+n+"a"+n+","+n+" 0 1,1 0,"+-2*n+"a"+n+","+n+" 0 1,1 0,"+2*n+"z"}function Ve(n,t){pc+=n,vc+=t,++dc}function Xe(){function n(n,r){var u=n-t,i=r-e,o=Math.sqrt(u*u+i*i);mc+=o*(t+n)/2,yc+=o*(e+r)/2,xc+=o,Ve(t=n,e=r)}var t,e;Rc.point=function(r,u){Rc.point=n,Ve(t=r,e=u)}}function $e(){Rc.point=Ve}function Be(){function n(n,t){var e=n-r,i=t-u,o=Math.sqrt(e*e+i*i);mc+=o*(r+n)/2,yc+=o*(u+t)/2,xc+=o,o=u*n-r*t,Mc+=o*(r+n),_c+=o*(u+t),bc+=3*o,Ve(r=n,u=t)}var t,e,r,u;Rc.point=function(i,o){Rc.point=n,Ve(t=r=i,e=u=o)},Rc.lineEnd=function(){n(t,e)}}function We(n){function t(t,e){n.moveTo(t,e),n.arc(t,e,o,0,wa)}function e(t,e){n.moveTo(t,e),a.point=r}function r(t,e){n.lineTo(t,e)}function u(){a.point=t}function i(){n.closePath()}var o=4.5,a={point:t,lineStart:function(){a.point=e},lineEnd:u,polygonStart:function(){a.lineEnd=i},polygonEnd:function(){a.lineEnd=u,a.point=t},pointRadius:function(n){return o=n,a},result:v};return a}function Je(n){function t(n){return(a?r:e)(n)}function e(t){return Qe(t,function(e,r){e=n(e,r),t.point(e[0],e[1])})}function r(t){function e(e,r){e=n(e,r),t.point(e[0],e[1])}function r(){x=0/0,S.point=i,t.lineStart()}function i(e,r){var i=le([e,r]),o=n(e,r);u(x,M,y,_,b,w,x=o[0],M=o[1],y=e,_=i[0],b=i[1],w=i[2],a,t),t.point(x,M)}function o(){S.point=e,t.lineEnd()}function c(){r(),S.point=s,S.lineEnd=l}function s(n,t){i(f=n,h=t),g=x,p=M,v=_,d=b,m=w,S.point=i}function l(){u(x,M,y,_,b,w,g,p,f,v,d,m,a,t),S.lineEnd=o,o()}var f,h,g,p,v,d,m,y,x,M,_,b,w,S={point:e,lineStart:r,lineEnd:o,polygonStart:function(){t.polygonStart(),S.lineStart=c},polygonEnd:function(){t.polygonEnd(),S.lineStart=r}};return S}function u(t,e,r,a,c,s,l,f,h,g,p,v,d,m){var y=l-t,x=f-e,M=y*y+x*x;if(M>4*i&&d--){var _=a+g,b=c+p,w=s+v,S=Math.sqrt(_*_+b*b+w*w),k=Math.asin(w/=S),E=ua(ua(w)-1)<ka||ua(r-h)<ka?(r+h)/2:Math.atan2(b,_),A=n(E,k),C=A[0],N=A[1],z=C-t,L=N-e,T=x*z-y*L;(T*T/M>i||ua((y*z+x*L)/M-.5)>.3||o>a*g+c*p+s*v)&&(u(t,e,r,a,c,s,C,N,E,_/=S,b/=S,w,d,m),m.point(C,N),u(C,N,E,_,b,w,l,f,h,g,p,v,d,m))}}var i=.5,o=Math.cos(30*Aa),a=16;
+return t.precision=function(n){return arguments.length?(a=(i=n*n)>0&&16,t):Math.sqrt(i)},t}function Ge(n){var t=Je(function(t,e){return n([t*Ca,e*Ca])});return function(n){return er(t(n))}}function Ke(n){this.stream=n}function Qe(n,t){return{point:t,sphere:function(){n.sphere()},lineStart:function(){n.lineStart()},lineEnd:function(){n.lineEnd()},polygonStart:function(){n.polygonStart()},polygonEnd:function(){n.polygonEnd()}}}function nr(n){return tr(function(){return n})()}function tr(n){function t(n){return n=a(n[0]*Aa,n[1]*Aa),[n[0]*h+c,s-n[1]*h]}function e(n){return n=a.invert((n[0]-c)/h,(s-n[1])/h),n&&[n[0]*Ca,n[1]*Ca]}function r(){a=je(o=ir(m,y,x),i);var n=i(v,d);return c=g-n[0]*h,s=p+n[1]*h,u()}function u(){return l&&(l.valid=!1,l=null),t}var i,o,a,c,s,l,f=Je(function(n,t){return n=i(n,t),[n[0]*h+c,s-n[1]*h]}),h=150,g=480,p=250,v=0,d=0,m=0,y=0,x=0,M=Sc,_=wt,b=null,w=null;return t.stream=function(n){return l&&(l.valid=!1),l=er(M(o,f(_(n)))),l.valid=!0,l},t.clipAngle=function(n){return arguments.length?(M=null==n?(b=n,Sc):De((b=+n)*Aa),u()):b},t.clipExtent=function(n){return arguments.length?(w=n,_=n?Ue(n[0][0],n[0][1],n[1][0],n[1][1]):wt,u()):w},t.scale=function(n){return arguments.length?(h=+n,r()):h},t.translate=function(n){return arguments.length?(g=+n[0],p=+n[1],r()):[g,p]},t.center=function(n){return arguments.length?(v=n[0]%360*Aa,d=n[1]%360*Aa,r()):[v*Ca,d*Ca]},t.rotate=function(n){return arguments.length?(m=n[0]%360*Aa,y=n[1]%360*Aa,x=n.length>2?n[2]%360*Aa:0,r()):[m*Ca,y*Ca,x*Ca]},Zo.rebind(t,f,"precision"),function(){return i=n.apply(this,arguments),t.invert=i.invert&&e,r()}}function er(n){return Qe(n,function(t,e){n.point(t*Aa,e*Aa)})}function rr(n,t){return[n,t]}function ur(n,t){return[n>ba?n-wa:-ba>n?n+wa:n,t]}function ir(n,t,e){return n?t||e?je(ar(n),cr(t,e)):ar(n):t||e?cr(t,e):ur}function or(n){return function(t,e){return t+=n,[t>ba?t-wa:-ba>t?t+wa:t,e]}}function ar(n){var t=or(n);return t.invert=or(-n),t}function cr(n,t){function e(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,s=Math.sin(t),l=s*r+a*u;return[Math.atan2(c*i-l*o,a*r-s*u),G(l*i+c*o)]}var r=Math.cos(n),u=Math.sin(n),i=Math.cos(t),o=Math.sin(t);return e.invert=function(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,s=Math.sin(t),l=s*i-c*o;return[Math.atan2(c*i+s*o,a*r+l*u),G(l*r-a*u)]},e}function sr(n,t){var e=Math.cos(n),r=Math.sin(n);return function(u,i,o,a){var c=o*t;null!=u?(u=lr(e,u),i=lr(e,i),(o>0?i>u:u>i)&&(u+=o*wa)):(u=n+o*wa,i=n-.5*c);for(var s,l=u;o>0?l>i:i>l;l-=c)a.point((s=de([e,-r*Math.cos(l),-r*Math.sin(l)]))[0],s[1])}}function lr(n,t){var e=le(t);e[0]-=n,ve(e);var r=J(-e[1]);return((-e[2]<0?-r:r)+2*Math.PI-ka)%(2*Math.PI)}function fr(n,t,e){var r=Zo.range(n,t-ka,e).concat(t);return function(n){return r.map(function(t){return[n,t]})}}function hr(n,t,e){var r=Zo.range(n,t-ka,e).concat(t);return function(n){return r.map(function(t){return[t,n]})}}function gr(n){return n.source}function pr(n){return n.target}function vr(n,t,e,r){var u=Math.cos(t),i=Math.sin(t),o=Math.cos(r),a=Math.sin(r),c=u*Math.cos(n),s=u*Math.sin(n),l=o*Math.cos(e),f=o*Math.sin(e),h=2*Math.asin(Math.sqrt(tt(r-t)+u*o*tt(e-n))),g=1/Math.sin(h),p=h?function(n){var t=Math.sin(n*=h)*g,e=Math.sin(h-n)*g,r=e*c+t*l,u=e*s+t*f,o=e*i+t*a;return[Math.atan2(u,r)*Ca,Math.atan2(o,Math.sqrt(r*r+u*u))*Ca]}:function(){return[n*Ca,t*Ca]};return p.distance=h,p}function dr(){function n(n,u){var i=Math.sin(u*=Aa),o=Math.cos(u),a=ua((n*=Aa)-t),c=Math.cos(a);Dc+=Math.atan2(Math.sqrt((a=o*Math.sin(a))*a+(a=r*i-e*o*c)*a),e*i+r*o*c),t=n,e=i,r=o}var t,e,r;Pc.point=function(u,i){t=u*Aa,e=Math.sin(i*=Aa),r=Math.cos(i),Pc.point=n},Pc.lineEnd=function(){Pc.point=Pc.lineEnd=v}}function mr(n,t){function e(t,e){var r=Math.cos(t),u=Math.cos(e),i=n(r*u);return[i*u*Math.sin(t),i*Math.sin(e)]}return e.invert=function(n,e){var r=Math.sqrt(n*n+e*e),u=t(r),i=Math.sin(u),o=Math.cos(u);return[Math.atan2(n*i,r*o),Math.asin(r&&e*i/r)]},e}function yr(n,t){function e(n,t){o>0?-Sa+ka>t&&(t=-Sa+ka):t>Sa-ka&&(t=Sa-ka);var e=o/Math.pow(u(t),i);return[e*Math.sin(i*n),o-e*Math.cos(i*n)]}var r=Math.cos(n),u=function(n){return Math.tan(ba/4+n/2)},i=n===t?Math.sin(n):Math.log(r/Math.cos(t))/Math.log(u(t)/u(n)),o=r*Math.pow(u(n),i)/i;return i?(e.invert=function(n,t){var e=o-t,r=B(i)*Math.sqrt(n*n+e*e);return[Math.atan2(n,e)/i,2*Math.atan(Math.pow(o/r,1/i))-Sa]},e):Mr}function xr(n,t){function e(n,t){var e=i-t;return[e*Math.sin(u*n),i-e*Math.cos(u*n)]}var r=Math.cos(n),u=n===t?Math.sin(n):(r-Math.cos(t))/(t-n),i=r/u+n;return ua(u)<ka?rr:(e.invert=function(n,t){var e=i-t;return[Math.atan2(n,e)/u,i-B(u)*Math.sqrt(n*n+e*e)]},e)}function Mr(n,t){return[n,Math.log(Math.tan(ba/4+t/2))]}function _r(n){var t,e=nr(n),r=e.scale,u=e.translate,i=e.clipExtent;return e.scale=function(){var n=r.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.translate=function(){var n=u.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.clipExtent=function(n){var o=i.apply(e,arguments);if(o===e){if(t=null==n){var a=ba*r(),c=u();i([[c[0]-a,c[1]-a],[c[0]+a,c[1]+a]])}}else t&&(o=null);return o},e.clipExtent(null)}function br(n,t){return[Math.log(Math.tan(ba/4+t/2)),-n]}function wr(n){return n[0]}function Sr(n){return n[1]}function kr(n){for(var t=n.length,e=[0,1],r=2,u=2;t>u;u++){for(;r>1&&W(n[e[r-2]],n[e[r-1]],n[u])<=0;)--r;e[r++]=u}return e.slice(0,r)}function Er(n,t){return n[0]-t[0]||n[1]-t[1]}function Ar(n,t,e){return(e[0]-t[0])*(n[1]-t[1])<(e[1]-t[1])*(n[0]-t[0])}function Cr(n,t,e,r){var u=n[0],i=e[0],o=t[0]-u,a=r[0]-i,c=n[1],s=e[1],l=t[1]-c,f=r[1]-s,h=(a*(c-s)-f*(u-i))/(f*o-a*l);return[u+h*o,c+h*l]}function Nr(n){var t=n[0],e=n[n.length-1];return!(t[0]-e[0]||t[1]-e[1])}function zr(){Gr(this),this.edge=this.site=this.circle=null}function Lr(n){var t=Bc.pop()||new zr;return t.site=n,t}function Tr(n){Yr(n),Vc.remove(n),Bc.push(n),Gr(n)}function qr(n){var t=n.circle,e=t.x,r=t.cy,u={x:e,y:r},i=n.P,o=n.N,a=[n];Tr(n);for(var c=i;c.circle&&ua(e-c.circle.x)<ka&&ua(r-c.circle.cy)<ka;)i=c.P,a.unshift(c),Tr(c),c=i;a.unshift(c),Yr(c);for(var s=o;s.circle&&ua(e-s.circle.x)<ka&&ua(r-s.circle.cy)<ka;)o=s.N,a.push(s),Tr(s),s=o;a.push(s),Yr(s);var l,f=a.length;for(l=1;f>l;++l)s=a[l],c=a[l-1],Br(s.edge,c.site,s.site,u);c=a[0],s=a[f-1],s.edge=Xr(c.site,s.site,null,u),Or(c),Or(s)}function Rr(n){for(var t,e,r,u,i=n.x,o=n.y,a=Vc._;a;)if(r=Dr(a,o)-i,r>ka)a=a.L;else{if(u=i-Pr(a,o),!(u>ka)){r>-ka?(t=a.P,e=a):u>-ka?(t=a,e=a.N):t=e=a;break}if(!a.R){t=a;break}a=a.R}var c=Lr(n);if(Vc.insert(t,c),t||e){if(t===e)return Yr(t),e=Lr(t.site),Vc.insert(c,e),c.edge=e.edge=Xr(t.site,c.site),Or(t),Or(e),void 0;if(!e)return c.edge=Xr(t.site,c.site),void 0;Yr(t),Yr(e);var s=t.site,l=s.x,f=s.y,h=n.x-l,g=n.y-f,p=e.site,v=p.x-l,d=p.y-f,m=2*(h*d-g*v),y=h*h+g*g,x=v*v+d*d,M={x:(d*y-g*x)/m+l,y:(h*x-v*y)/m+f};Br(e.edge,s,p,M),c.edge=Xr(s,n,null,M),e.edge=Xr(n,p,null,M),Or(t),Or(e)}}function Dr(n,t){var e=n.site,r=e.x,u=e.y,i=u-t;if(!i)return r;var o=n.P;if(!o)return-1/0;e=o.site;var a=e.x,c=e.y,s=c-t;if(!s)return a;var l=a-r,f=1/i-1/s,h=l/s;return f?(-h+Math.sqrt(h*h-2*f*(l*l/(-2*s)-c+s/2+u-i/2)))/f+r:(r+a)/2}function Pr(n,t){var e=n.N;if(e)return Dr(e,t);var r=n.site;return r.y===t?r.x:1/0}function Ur(n){this.site=n,this.edges=[]}function jr(n){for(var t,e,r,u,i,o,a,c,s,l,f=n[0][0],h=n[1][0],g=n[0][1],p=n[1][1],v=Zc,d=v.length;d--;)if(i=v[d],i&&i.prepare())for(a=i.edges,c=a.length,o=0;c>o;)l=a[o].end(),r=l.x,u=l.y,s=a[++o%c].start(),t=s.x,e=s.y,(ua(r-t)>ka||ua(u-e)>ka)&&(a.splice(o,0,new Wr($r(i.site,l,ua(r-f)<ka&&p-u>ka?{x:f,y:ua(t-f)<ka?e:p}:ua(u-p)<ka&&h-r>ka?{x:ua(e-p)<ka?t:h,y:p}:ua(r-h)<ka&&u-g>ka?{x:h,y:ua(t-h)<ka?e:g}:ua(u-g)<ka&&r-f>ka?{x:ua(e-g)<ka?t:f,y:g}:null),i.site,null)),++c)}function Hr(n,t){return t.angle-n.angle}function Fr(){Gr(this),this.x=this.y=this.arc=this.site=this.cy=null}function Or(n){var t=n.P,e=n.N;if(t&&e){var r=t.site,u=n.site,i=e.site;if(r!==i){var o=u.x,a=u.y,c=r.x-o,s=r.y-a,l=i.x-o,f=i.y-a,h=2*(c*f-s*l);if(!(h>=-Ea)){var g=c*c+s*s,p=l*l+f*f,v=(f*g-s*p)/h,d=(c*p-l*g)/h,f=d+a,m=Wc.pop()||new Fr;m.arc=n,m.site=u,m.x=v+o,m.y=f+Math.sqrt(v*v+d*d),m.cy=f,n.circle=m;for(var y=null,x=$c._;x;)if(m.y<x.y||m.y===x.y&&m.x<=x.x){if(!x.L){y=x.P;break}x=x.L}else{if(!x.R){y=x;break}x=x.R}$c.insert(y,m),y||(Xc=m)}}}}function Yr(n){var t=n.circle;t&&(t.P||(Xc=t.N),$c.remove(t),Wc.push(t),Gr(t),n.circle=null)}function Ir(n){for(var t,e=Ic,r=Pe(n[0][0],n[0][1],n[1][0],n[1][1]),u=e.length;u--;)t=e[u],(!Zr(t,n)||!r(t)||ua(t.a.x-t.b.x)<ka&&ua(t.a.y-t.b.y)<ka)&&(t.a=t.b=null,e.splice(u,1))}function Zr(n,t){var e=n.b;if(e)return!0;var r,u,i=n.a,o=t[0][0],a=t[1][0],c=t[0][1],s=t[1][1],l=n.l,f=n.r,h=l.x,g=l.y,p=f.x,v=f.y,d=(h+p)/2,m=(g+v)/2;if(v===g){if(o>d||d>=a)return;if(h>p){if(i){if(i.y>=s)return}else i={x:d,y:c};e={x:d,y:s}}else{if(i){if(i.y<c)return}else i={x:d,y:s};e={x:d,y:c}}}else if(r=(h-p)/(v-g),u=m-r*d,-1>r||r>1)if(h>p){if(i){if(i.y>=s)return}else i={x:(c-u)/r,y:c};e={x:(s-u)/r,y:s}}else{if(i){if(i.y<c)return}else i={x:(s-u)/r,y:s};e={x:(c-u)/r,y:c}}else if(v>g){if(i){if(i.x>=a)return}else i={x:o,y:r*o+u};e={x:a,y:r*a+u}}else{if(i){if(i.x<o)return}else i={x:a,y:r*a+u};e={x:o,y:r*o+u}}return n.a=i,n.b=e,!0}function Vr(n,t){this.l=n,this.r=t,this.a=this.b=null}function Xr(n,t,e,r){var u=new Vr(n,t);return Ic.push(u),e&&Br(u,n,t,e),r&&Br(u,t,n,r),Zc[n.i].edges.push(new Wr(u,n,t)),Zc[t.i].edges.push(new Wr(u,t,n)),u}function $r(n,t,e){var r=new Vr(n,null);return r.a=t,r.b=e,Ic.push(r),r}function Br(n,t,e,r){n.a||n.b?n.l===e?n.b=r:n.a=r:(n.a=r,n.l=t,n.r=e)}function Wr(n,t,e){var r=n.a,u=n.b;this.edge=n,this.site=t,this.angle=e?Math.atan2(e.y-t.y,e.x-t.x):n.l===t?Math.atan2(u.x-r.x,r.y-u.y):Math.atan2(r.x-u.x,u.y-r.y)}function Jr(){this._=null}function Gr(n){n.U=n.C=n.L=n.R=n.P=n.N=null}function Kr(n,t){var e=t,r=t.R,u=e.U;u?u.L===e?u.L=r:u.R=r:n._=r,r.U=u,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function Qr(n,t){var e=t,r=t.L,u=e.U;u?u.L===e?u.L=r:u.R=r:n._=r,r.U=u,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function nu(n){for(;n.L;)n=n.L;return n}function tu(n,t){var e,r,u,i=n.sort(eu).pop();for(Ic=[],Zc=new Array(n.length),Vc=new Jr,$c=new Jr;;)if(u=Xc,i&&(!u||i.y<u.y||i.y===u.y&&i.x<u.x))(i.x!==e||i.y!==r)&&(Zc[i.i]=new Ur(i),Rr(i),e=i.x,r=i.y),i=n.pop();else{if(!u)break;qr(u.arc)}t&&(Ir(t),jr(t));var o={cells:Zc,edges:Ic};return Vc=$c=Ic=Zc=null,o}function eu(n,t){return t.y-n.y||t.x-n.x}function ru(n,t,e){return(n.x-e.x)*(t.y-n.y)-(n.x-t.x)*(e.y-n.y)}function uu(n){return n.x}function iu(n){return n.y}function ou(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}function au(n,t,e,r,u,i){if(!n(t,e,r,u,i)){var o=.5*(e+u),a=.5*(r+i),c=t.nodes;c[0]&&au(n,c[0],e,r,o,a),c[1]&&au(n,c[1],o,r,u,a),c[2]&&au(n,c[2],e,a,o,i),c[3]&&au(n,c[3],o,a,u,i)}}function cu(n,t){n=Zo.rgb(n),t=Zo.rgb(t);var e=n.r,r=n.g,u=n.b,i=t.r-e,o=t.g-r,a=t.b-u;return function(n){return"#"+dt(Math.round(e+i*n))+dt(Math.round(r+o*n))+dt(Math.round(u+a*n))}}function su(n,t){var e,r={},u={};for(e in n)e in t?r[e]=hu(n[e],t[e]):u[e]=n[e];for(e in t)e in n||(u[e]=t[e]);return function(n){for(e in r)u[e]=r[e](n);return u}}function lu(n,t){return t-=n=+n,function(e){return n+t*e}}function fu(n,t){var e,r,u,i=Gc.lastIndex=Kc.lastIndex=0,o=-1,a=[],c=[];for(n+="",t+="";(e=Gc.exec(n))&&(r=Kc.exec(t));)(u=r.index)>i&&(u=t.substring(i,u),a[o]?a[o]+=u:a[++o]=u),(e=e[0])===(r=r[0])?a[o]?a[o]+=r:a[++o]=r:(a[++o]=null,c.push({i:o,x:lu(e,r)})),i=Kc.lastIndex;return i<t.length&&(u=t.substring(i),a[o]?a[o]+=u:a[++o]=u),a.length<2?c[0]?(t=c[0].x,function(n){return t(n)+""}):function(){return t}:(t=c.length,function(n){for(var e,r=0;t>r;++r)a[(e=c[r]).i]=e.x(n);return a.join("")})}function hu(n,t){for(var e,r=Zo.interpolators.length;--r>=0&&!(e=Zo.interpolators[r](n,t)););return e}function gu(n,t){var e,r=[],u=[],i=n.length,o=t.length,a=Math.min(n.length,t.length);for(e=0;a>e;++e)r.push(hu(n[e],t[e]));for(;i>e;++e)u[e]=n[e];for(;o>e;++e)u[e]=t[e];return function(n){for(e=0;a>e;++e)u[e]=r[e](n);return u}}function pu(n){return function(t){return 0>=t?0:t>=1?1:n(t)}}function vu(n){return function(t){return 1-n(1-t)}}function du(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function mu(n){return n*n}function yu(n){return n*n*n}function xu(n){if(0>=n)return 0;if(n>=1)return 1;var t=n*n,e=t*n;return 4*(.5>n?e:3*(n-t)+e-.75)}function Mu(n){return function(t){return Math.pow(t,n)}}function _u(n){return 1-Math.cos(n*Sa)}function bu(n){return Math.pow(2,10*(n-1))}function wu(n){return 1-Math.sqrt(1-n*n)}function Su(n,t){var e;return arguments.length<2&&(t=.45),arguments.length?e=t/wa*Math.asin(1/n):(n=1,e=t/4),function(r){return 1+n*Math.pow(2,-10*r)*Math.sin((r-e)*wa/t)}}function ku(n){return n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function Eu(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*n+.75:2.5/2.75>n?7.5625*(n-=2.25/2.75)*n+.9375:7.5625*(n-=2.625/2.75)*n+.984375}function Au(n,t){n=Zo.hcl(n),t=Zo.hcl(t);var e=n.h,r=n.c,u=n.l,i=t.h-e,o=t.c-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.c:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return ot(e+i*n,r+o*n,u+a*n)+""}}function Cu(n,t){n=Zo.hsl(n),t=Zo.hsl(t);var e=n.h,r=n.s,u=n.l,i=t.h-e,o=t.s-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.s:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return ut(e+i*n,r+o*n,u+a*n)+""}}function Nu(n,t){n=Zo.lab(n),t=Zo.lab(t);var e=n.l,r=n.a,u=n.b,i=t.l-e,o=t.a-r,a=t.b-u;return function(n){return ct(e+i*n,r+o*n,u+a*n)+""}}function zu(n,t){return t-=n,function(e){return Math.round(n+t*e)}}function Lu(n){var t=[n.a,n.b],e=[n.c,n.d],r=qu(t),u=Tu(t,e),i=qu(Ru(e,t,-u))||0;t[0]*e[1]<e[0]*t[1]&&(t[0]*=-1,t[1]*=-1,r*=-1,u*=-1),this.rotate=(r?Math.atan2(t[1],t[0]):Math.atan2(-e[0],e[1]))*Ca,this.translate=[n.e,n.f],this.scale=[r,i],this.skew=i?Math.atan2(u,i)*Ca:0}function Tu(n,t){return n[0]*t[0]+n[1]*t[1]}function qu(n){var t=Math.sqrt(Tu(n,n));return t&&(n[0]/=t,n[1]/=t),t}function Ru(n,t,e){return n[0]+=e*t[0],n[1]+=e*t[1],n}function Du(n,t){var e,r=[],u=[],i=Zo.transform(n),o=Zo.transform(t),a=i.translate,c=o.translate,s=i.rotate,l=o.rotate,f=i.skew,h=o.skew,g=i.scale,p=o.scale;return a[0]!=c[0]||a[1]!=c[1]?(r.push("translate(",null,",",null,")"),u.push({i:1,x:lu(a[0],c[0])},{i:3,x:lu(a[1],c[1])})):c[0]||c[1]?r.push("translate("+c+")"):r.push(""),s!=l?(s-l>180?l+=360:l-s>180&&(s+=360),u.push({i:r.push(r.pop()+"rotate(",null,")")-2,x:lu(s,l)})):l&&r.push(r.pop()+"rotate("+l+")"),f!=h?u.push({i:r.push(r.pop()+"skewX(",null,")")-2,x:lu(f,h)}):h&&r.push(r.pop()+"skewX("+h+")"),g[0]!=p[0]||g[1]!=p[1]?(e=r.push(r.pop()+"scale(",null,",",null,")"),u.push({i:e-4,x:lu(g[0],p[0])},{i:e-2,x:lu(g[1],p[1])})):(1!=p[0]||1!=p[1])&&r.push(r.pop()+"scale("+p+")"),e=u.length,function(n){for(var t,i=-1;++i<e;)r[(t=u[i]).i]=t.x(n);return r.join("")}}function Pu(n,t){return t=t-(n=+n)?1/(t-n):0,function(e){return(e-n)*t}}function Uu(n,t){return t=t-(n=+n)?1/(t-n):0,function(e){return Math.max(0,Math.min(1,(e-n)*t))}}function ju(n){for(var t=n.source,e=n.target,r=Fu(t,e),u=[t];t!==r;)t=t.parent,u.push(t);for(var i=u.length;e!==r;)u.splice(i,0,e),e=e.parent;return u}function Hu(n){for(var t=[],e=n.parent;null!=e;)t.push(n),n=e,e=e.parent;return t.push(n),t}function Fu(n,t){if(n===t)return n;for(var e=Hu(n),r=Hu(t),u=e.pop(),i=r.pop(),o=null;u===i;)o=u,u=e.pop(),i=r.pop();return o}function Ou(n){n.fixed|=2}function Yu(n){n.fixed&=-7}function Iu(n){n.fixed|=4,n.px=n.x,n.py=n.y}function Zu(n){n.fixed&=-5}function Vu(n,t,e){var r=0,u=0;if(n.charge=0,!n.leaf)for(var i,o=n.nodes,a=o.length,c=-1;++c<a;)i=o[c],null!=i&&(Vu(i,t,e),n.charge+=i.charge,r+=i.charge*i.cx,u+=i.charge*i.cy);if(n.point){n.leaf||(n.point.x+=Math.random()-.5,n.point.y+=Math.random()-.5);var s=t*e[n.point.index];n.charge+=n.pointCharge=s,r+=s*n.point.x,u+=s*n.point.y}n.cx=r/n.charge,n.cy=u/n.charge}function Xu(n,t){return Zo.rebind(n,t,"sort","children","value"),n.nodes=n,n.links=Ku,n}function $u(n,t){for(var e=[n];null!=(n=e.pop());)if(t(n),(u=n.children)&&(r=u.length))for(var r,u;--r>=0;)e.push(u[r])}function Bu(n,t){for(var e=[n],r=[];null!=(n=e.pop());)if(r.push(n),(i=n.children)&&(u=i.length))for(var u,i,o=-1;++o<u;)e.push(i[o]);for(;null!=(n=r.pop());)t(n)}function Wu(n){return n.children}function Ju(n){return n.value}function Gu(n,t){return t.value-n.value}function Ku(n){return Zo.merge(n.map(function(n){return(n.children||[]).map(function(t){return{source:n,target:t}})}))}function Qu(n){return n.x}function ni(n){return n.y}function ti(n,t,e){n.y0=t,n.y=e}function ei(n){return Zo.range(n.length)}function ri(n){for(var t=-1,e=n[0].length,r=[];++t<e;)r[t]=0;return r}function ui(n){for(var t,e=1,r=0,u=n[0][1],i=n.length;i>e;++e)(t=n[e][1])>u&&(r=e,u=t);return r}function ii(n){return n.reduce(oi,0)}function oi(n,t){return n+t[1]}function ai(n,t){return ci(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function ci(n,t){for(var e=-1,r=+n[0],u=(n[1]-r)/t,i=[];++e<=t;)i[e]=u*e+r;return i}function si(n){return[Zo.min(n),Zo.max(n)]}function li(n,t){return n.value-t.value}function fi(n,t){var e=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=e,e._pack_prev=t}function hi(n,t){n._pack_next=t,t._pack_prev=n}function gi(n,t){var e=t.x-n.x,r=t.y-n.y,u=n.r+t.r;return.999*u*u>e*e+r*r}function pi(n){function t(n){l=Math.min(n.x-n.r,l),f=Math.max(n.x+n.r,f),h=Math.min(n.y-n.r,h),g=Math.max(n.y+n.r,g)}if((e=n.children)&&(s=e.length)){var e,r,u,i,o,a,c,s,l=1/0,f=-1/0,h=1/0,g=-1/0;if(e.forEach(vi),r=e[0],r.x=-r.r,r.y=0,t(r),s>1&&(u=e[1],u.x=u.r,u.y=0,t(u),s>2))for(i=e[2],yi(r,u,i),t(i),fi(r,i),r._pack_prev=i,fi(i,u),u=r._pack_next,o=3;s>o;o++){yi(r,u,i=e[o]);var p=0,v=1,d=1;for(a=u._pack_next;a!==u;a=a._pack_next,v++)if(gi(a,i)){p=1;break}if(1==p)for(c=r._pack_prev;c!==a._pack_prev&&!gi(c,i);c=c._pack_prev,d++);p?(d>v||v==d&&u.r<r.r?hi(r,u=a):hi(r=c,u),o--):(fi(r,i),u=i,t(i))}var m=(l+f)/2,y=(h+g)/2,x=0;for(o=0;s>o;o++)i=e[o],i.x-=m,i.y-=y,x=Math.max(x,i.r+Math.sqrt(i.x*i.x+i.y*i.y));n.r=x,e.forEach(di)}}function vi(n){n._pack_next=n._pack_prev=n}function di(n){delete n._pack_next,delete n._pack_prev}function mi(n,t,e,r){var u=n.children;if(n.x=t+=r*n.x,n.y=e+=r*n.y,n.r*=r,u)for(var i=-1,o=u.length;++i<o;)mi(u[i],t,e,r)}function yi(n,t,e){var r=n.r+e.r,u=t.x-n.x,i=t.y-n.y;if(r&&(u||i)){var o=t.r+e.r,a=u*u+i*i;o*=o,r*=r;var c=.5+(r-o)/(2*a),s=Math.sqrt(Math.max(0,2*o*(r+a)-(r-=a)*r-o*o))/(2*a);e.x=n.x+c*u+s*i,e.y=n.y+c*i-s*u}else e.x=n.x+r,e.y=n.y}function xi(n,t){return n.parent==t.parent?1:2}function Mi(n){var t=n.children;return t.length?t[0]:n.t}function _i(n){var t,e=n.children;return(t=e.length)?e[t-1]:n.t}function bi(n,t,e){var r=e/(t.i-n.i);t.c-=r,t.s+=e,n.c+=r,t.z+=e,t.m+=e}function wi(n){for(var t,e=0,r=0,u=n.children,i=u.length;--i>=0;)t=u[i],t.z+=e,t.m+=e,e+=t.s+(r+=t.c)}function Si(n,t,e){return n.a.parent===t.parent?n.a:e}function ki(n){return 1+Zo.max(n,function(n){return n.y})}function Ei(n){return n.reduce(function(n,t){return n+t.x},0)/n.length}function Ai(n){var t=n.children;return t&&t.length?Ai(t[0]):n}function Ci(n){var t,e=n.children;return e&&(t=e.length)?Ci(e[t-1]):n}function Ni(n){return{x:n.x,y:n.y,dx:n.dx,dy:n.dy}}function zi(n,t){var e=n.x+t[3],r=n.y+t[0],u=n.dx-t[1]-t[3],i=n.dy-t[0]-t[2];return 0>u&&(e+=u/2,u=0),0>i&&(r+=i/2,i=0),{x:e,y:r,dx:u,dy:i}}function Li(n){var t=n[0],e=n[n.length-1];return e>t?[t,e]:[e,t]}function Ti(n){return n.rangeExtent?n.rangeExtent():Li(n.range())}function qi(n,t,e,r){var u=e(n[0],n[1]),i=r(t[0],t[1]);return function(n){return i(u(n))}}function Ri(n,t){var e,r=0,u=n.length-1,i=n[r],o=n[u];return i>o&&(e=r,r=u,u=e,e=i,i=o,o=e),n[r]=t.floor(i),n[u]=t.ceil(o),n}function Di(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return Math.ceil(t/n)*n}}:ss}function Pi(n,t,e,r){var u=[],i=[],o=0,a=Math.min(n.length,t.length)-1;for(n[a]<n[0]&&(n=n.slice().reverse(),t=t.slice().reverse());++o<=a;)u.push(e(n[o-1],n[o])),i.push(r(t[o-1],t[o]));return function(t){var e=Zo.bisect(n,t,1,a)-1;return i[e](u[e](t))}}function Ui(n,t,e,r){function u(){var u=Math.min(n.length,t.length)>2?Pi:qi,c=r?Uu:Pu;return o=u(n,t,c,e),a=u(t,n,c,hu),i}function i(n){return o(n)}var o,a;return i.invert=function(n){return a(n)},i.domain=function(t){return arguments.length?(n=t.map(Number),u()):n},i.range=function(n){return arguments.length?(t=n,u()):t},i.rangeRound=function(n){return i.range(n).interpolate(zu)},i.clamp=function(n){return arguments.length?(r=n,u()):r},i.interpolate=function(n){return arguments.length?(e=n,u()):e},i.ticks=function(t){return Oi(n,t)},i.tickFormat=function(t,e){return Yi(n,t,e)},i.nice=function(t){return Hi(n,t),u()},i.copy=function(){return Ui(n,t,e,r)},u()}function ji(n,t){return Zo.rebind(n,t,"range","rangeRound","interpolate","clamp")}function Hi(n,t){return Ri(n,Di(Fi(n,t)[2]))}function Fi(n,t){null==t&&(t=10);var e=Li(n),r=e[1]-e[0],u=Math.pow(10,Math.floor(Math.log(r/t)/Math.LN10)),i=t/r*u;return.15>=i?u*=10:.35>=i?u*=5:.75>=i&&(u*=2),e[0]=Math.ceil(e[0]/u)*u,e[1]=Math.floor(e[1]/u)*u+.5*u,e[2]=u,e}function Oi(n,t){return Zo.range.apply(Zo,Fi(n,t))}function Yi(n,t,e){var r=Fi(n,t);if(e){var u=Ga.exec(e);if(u.shift(),"s"===u[8]){var i=Zo.formatPrefix(Math.max(ua(r[0]),ua(r[1])));return u[7]||(u[7]="."+Ii(i.scale(r[2]))),u[8]="f",e=Zo.format(u.join("")),function(n){return e(i.scale(n))+i.symbol}}u[7]||(u[7]="."+Zi(u[8],r)),e=u.join("")}else e=",."+Ii(r[2])+"f";return Zo.format(e)}function Ii(n){return-Math.floor(Math.log(n)/Math.LN10+.01)}function Zi(n,t){var e=Ii(t[2]);return n in ls?Math.abs(e-Ii(Math.max(ua(t[0]),ua(t[1]))))+ +("e"!==n):e-2*("%"===n)}function Vi(n,t,e,r){function u(n){return(e?Math.log(0>n?0:n):-Math.log(n>0?0:-n))/Math.log(t)}function i(n){return e?Math.pow(t,n):-Math.pow(t,-n)}function o(t){return n(u(t))}return o.invert=function(t){return i(n.invert(t))},o.domain=function(t){return arguments.length?(e=t[0]>=0,n.domain((r=t.map(Number)).map(u)),o):r},o.base=function(e){return arguments.length?(t=+e,n.domain(r.map(u)),o):t},o.nice=function(){var t=Ri(r.map(u),e?Math:hs);return n.domain(t),r=t.map(i),o},o.ticks=function(){var n=Li(r),o=[],a=n[0],c=n[1],s=Math.floor(u(a)),l=Math.ceil(u(c)),f=t%1?2:t;if(isFinite(l-s)){if(e){for(;l>s;s++)for(var h=1;f>h;h++)o.push(i(s)*h);o.push(i(s))}else for(o.push(i(s));s++<l;)for(var h=f-1;h>0;h--)o.push(i(s)*h);for(s=0;o[s]<a;s++);for(l=o.length;o[l-1]>c;l--);o=o.slice(s,l)}return o},o.tickFormat=function(n,t){if(!arguments.length)return fs;arguments.length<2?t=fs:"function"!=typeof t&&(t=Zo.format(t));var r,a=Math.max(.1,n/o.ticks().length),c=e?(r=1e-12,Math.ceil):(r=-1e-12,Math.floor);return function(n){return n/i(c(u(n)+r))<=a?t(n):""}},o.copy=function(){return Vi(n.copy(),t,e,r)},ji(o,n)}function Xi(n,t,e){function r(t){return n(u(t))}var u=$i(t),i=$i(1/t);return r.invert=function(t){return i(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain((e=t.map(Number)).map(u)),r):e},r.ticks=function(n){return Oi(e,n)},r.tickFormat=function(n,t){return Yi(e,n,t)},r.nice=function(n){return r.domain(Hi(e,n))},r.exponent=function(o){return arguments.length?(u=$i(t=o),i=$i(1/t),n.domain(e.map(u)),r):t},r.copy=function(){return Xi(n.copy(),t,e)},ji(r,n)}function $i(n){return function(t){return 0>t?-Math.pow(-t,n):Math.pow(t,n)}}function Bi(n,t){function e(e){return i[((u.get(e)||("range"===t.t?u.set(e,n.push(e)):0/0))-1)%i.length]}function r(t,e){return Zo.range(n.length).map(function(n){return t+e*n})}var u,i,a;return e.domain=function(r){if(!arguments.length)return n;n=[],u=new o;for(var i,a=-1,c=r.length;++a<c;)u.has(i=r[a])||u.set(i,n.push(i));return e[t.t].apply(e,t.a)},e.range=function(n){return arguments.length?(i=n,a=0,t={t:"range",a:arguments},e):i},e.rangePoints=function(u,o){arguments.length<2&&(o=0);var c=u[0],s=u[1],l=(s-c)/(Math.max(1,n.length-1)+o);return i=r(n.length<2?(c+s)/2:c+l*o/2,l),a=0,t={t:"rangePoints",a:arguments},e},e.rangeBands=function(u,o,c){arguments.length<2&&(o=0),arguments.length<3&&(c=o);var s=u[1]<u[0],l=u[s-0],f=u[1-s],h=(f-l)/(n.length-o+2*c);return i=r(l+h*c,h),s&&i.reverse(),a=h*(1-o),t={t:"rangeBands",a:arguments},e},e.rangeRoundBands=function(u,o,c){arguments.length<2&&(o=0),arguments.length<3&&(c=o);var s=u[1]<u[0],l=u[s-0],f=u[1-s],h=Math.floor((f-l)/(n.length-o+2*c)),g=f-l-(n.length-o)*h;return i=r(l+Math.round(g/2),h),s&&i.reverse(),a=Math.round(h*(1-o)),t={t:"rangeRoundBands",a:arguments},e},e.rangeBand=function(){return a},e.rangeExtent=function(){return Li(t.a[0])},e.copy=function(){return Bi(n,t)},e.domain(n)}function Wi(e,r){function u(){var n=0,t=r.length;for(o=[];++n<t;)o[n-1]=Zo.quantile(e,n/t);return i}function i(n){return isNaN(n=+n)?void 0:r[Zo.bisect(o,n)]}var o;return i.domain=function(r){return arguments.length?(e=r.filter(t).sort(n),u()):e},i.range=function(n){return arguments.length?(r=n,u()):r},i.quantiles=function(){return o},i.invertExtent=function(n){return n=r.indexOf(n),0>n?[0/0,0/0]:[n>0?o[n-1]:e[0],n<o.length?o[n]:e[e.length-1]]},i.copy=function(){return Wi(e,r)},u()}function Ji(n,t,e){function r(t){return e[Math.max(0,Math.min(o,Math.floor(i*(t-n))))]}function u(){return i=e.length/(t-n),o=e.length-1,r}var i,o;return r.domain=function(e){return arguments.length?(n=+e[0],t=+e[e.length-1],u()):[n,t]},r.range=function(n){return arguments.length?(e=n,u()):e},r.invertExtent=function(t){return t=e.indexOf(t),t=0>t?0/0:t/i+n,[t,t+1/i]},r.copy=function(){return Ji(n,t,e)},u()}function Gi(n,t){function e(e){return e>=e?t[Zo.bisect(n,e)]:void 0}return e.domain=function(t){return arguments.length?(n=t,e):n},e.range=function(n){return arguments.length?(t=n,e):t},e.invertExtent=function(e){return e=t.indexOf(e),[n[e-1],n[e]]},e.copy=function(){return Gi(n,t)},e}function Ki(n){function t(n){return+n}return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=e.map(t),t):n},t.ticks=function(t){return Oi(n,t)},t.tickFormat=function(t,e){return Yi(n,t,e)},t.copy=function(){return Ki(n)},t}function Qi(n){return n.innerRadius}function no(n){return n.outerRadius}function to(n){return n.startAngle}function eo(n){return n.endAngle}function ro(n){function t(t){function o(){s.push("M",i(n(l),a))}for(var c,s=[],l=[],f=-1,h=t.length,g=bt(e),p=bt(r);++f<h;)u.call(this,c=t[f],f)?l.push([+g.call(this,c,f),+p.call(this,c,f)]):l.length&&(o(),l=[]);return l.length&&o(),s.length?s.join(""):null}var e=wr,r=Sr,u=we,i=uo,o=i.key,a=.7;return t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t.defined=function(n){return arguments.length?(u=n,t):u},t.interpolate=function(n){return arguments.length?(o="function"==typeof n?i=n:(i=xs.get(n)||uo).key,t):o},t.tension=function(n){return arguments.length?(a=n,t):a},t}function uo(n){return n.join("L")}function io(n){return uo(n)+"Z"}function oo(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("H",(r[0]+(r=n[t])[0])/2,"V",r[1]);return e>1&&u.push("H",r[0]),u.join("")}function ao(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("V",(r=n[t])[1],"H",r[0]);return u.join("")}function co(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("H",(r=n[t])[0],"V",r[1]);return u.join("")}function so(n,t){return n.length<4?uo(n):n[1]+ho(n.slice(1,n.length-1),go(n,t))}function lo(n,t){return n.length<3?uo(n):n[0]+ho((n.push(n[0]),n),go([n[n.length-2]].concat(n,[n[1]]),t))}function fo(n,t){return n.length<3?uo(n):n[0]+ho(n,go(n,t))}function ho(n,t){if(t.length<1||n.length!=t.length&&n.length!=t.length+2)return uo(n);var e=n.length!=t.length,r="",u=n[0],i=n[1],o=t[0],a=o,c=1;if(e&&(r+="Q"+(i[0]-2*o[0]/3)+","+(i[1]-2*o[1]/3)+","+i[0]+","+i[1],u=n[1],c=2),t.length>1){a=t[1],i=n[c],c++,r+="C"+(u[0]+o[0])+","+(u[1]+o[1])+","+(i[0]-a[0])+","+(i[1]-a[1])+","+i[0]+","+i[1];for(var s=2;s<t.length;s++,c++)i=n[c],a=t[s],r+="S"+(i[0]-a[0])+","+(i[1]-a[1])+","+i[0]+","+i[1]}if(e){var l=n[c];r+="Q"+(i[0]+2*a[0]/3)+","+(i[1]+2*a[1]/3)+","+l[0]+","+l[1]}return r}function go(n,t){for(var e,r=[],u=(1-t)/2,i=n[0],o=n[1],a=1,c=n.length;++a<c;)e=i,i=o,o=n[a],r.push([u*(o[0]-e[0]),u*(o[1]-e[1])]);return r}function po(n){if(n.length<3)return uo(n);var t=1,e=n.length,r=n[0],u=r[0],i=r[1],o=[u,u,u,(r=n[1])[0]],a=[i,i,i,r[1]],c=[u,",",i,"L",xo(bs,o),",",xo(bs,a)];for(n.push(n[e-1]);++t<=e;)r=n[t],o.shift(),o.push(r[0]),a.shift(),a.push(r[1]),Mo(c,o,a);return n.pop(),c.push("L",r),c.join("")}function vo(n){if(n.length<4)return uo(n);for(var t,e=[],r=-1,u=n.length,i=[0],o=[0];++r<3;)t=n[r],i.push(t[0]),o.push(t[1]);for(e.push(xo(bs,i)+","+xo(bs,o)),--r;++r<u;)t=n[r],i.shift(),i.push(t[0]),o.shift(),o.push(t[1]),Mo(e,i,o);return e.join("")}function mo(n){for(var t,e,r=-1,u=n.length,i=u+4,o=[],a=[];++r<4;)e=n[r%u],o.push(e[0]),a.push(e[1]);for(t=[xo(bs,o),",",xo(bs,a)],--r;++r<i;)e=n[r%u],o.shift(),o.push(e[0]),a.shift(),a.push(e[1]),Mo(t,o,a);return t.join("")}function yo(n,t){var e=n.length-1;if(e)for(var r,u,i=n[0][0],o=n[0][1],a=n[e][0]-i,c=n[e][1]-o,s=-1;++s<=e;)r=n[s],u=s/e,r[0]=t*r[0]+(1-t)*(i+u*a),r[1]=t*r[1]+(1-t)*(o+u*c);return po(n)}function xo(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]+n[3]*t[3]}function Mo(n,t,e){n.push("C",xo(Ms,t),",",xo(Ms,e),",",xo(_s,t),",",xo(_s,e),",",xo(bs,t),",",xo(bs,e))}function _o(n,t){return(t[1]-n[1])/(t[0]-n[0])}function bo(n){for(var t=0,e=n.length-1,r=[],u=n[0],i=n[1],o=r[0]=_o(u,i);++t<e;)r[t]=(o+(o=_o(u=i,i=n[t+1])))/2;return r[t]=o,r}function wo(n){for(var t,e,r,u,i=[],o=bo(n),a=-1,c=n.length-1;++a<c;)t=_o(n[a],n[a+1]),ua(t)<ka?o[a]=o[a+1]=0:(e=o[a]/t,r=o[a+1]/t,u=e*e+r*r,u>9&&(u=3*t/Math.sqrt(u),o[a]=u*e,o[a+1]=u*r));for(a=-1;++a<=c;)u=(n[Math.min(c,a+1)][0]-n[Math.max(0,a-1)][0])/(6*(1+o[a]*o[a])),i.push([u||0,o[a]*u||0]);return i}function So(n){return n.length<3?uo(n):n[0]+ho(n,wo(n))}function ko(n){for(var t,e,r,u=-1,i=n.length;++u<i;)t=n[u],e=t[0],r=t[1]+ms,t[0]=e*Math.cos(r),t[1]=e*Math.sin(r);return n}function Eo(n){function t(t){function c(){v.push("M",a(n(m),f),l,s(n(d.reverse()),f),"Z")}for(var h,g,p,v=[],d=[],m=[],y=-1,x=t.length,M=bt(e),_=bt(u),b=e===r?function(){return g}:bt(r),w=u===i?function(){return p}:bt(i);++y<x;)o.call(this,h=t[y],y)?(d.push([g=+M.call(this,h,y),p=+_.call(this,h,y)]),m.push([+b.call(this,h,y),+w.call(this,h,y)])):d.length&&(c(),d=[],m=[]);return d.length&&c(),v.length?v.join(""):null}var e=wr,r=wr,u=0,i=Sr,o=we,a=uo,c=a.key,s=a,l="L",f=.7;return t.x=function(n){return arguments.length?(e=r=n,t):r},t.x0=function(n){return arguments.length?(e=n,t):e},t.x1=function(n){return arguments.length?(r=n,t):r},t.y=function(n){return arguments.length?(u=i=n,t):i},t.y0=function(n){return arguments.length?(u=n,t):u},t.y1=function(n){return arguments.length?(i=n,t):i},t.defined=function(n){return arguments.length?(o=n,t):o},t.interpolate=function(n){return arguments.length?(c="function"==typeof n?a=n:(a=xs.get(n)||uo).key,s=a.reverse||a,l=a.closed?"M":"L",t):c},t.tension=function(n){return arguments.length?(f=n,t):f},t}function Ao(n){return n.radius}function Co(n){return[n.x,n.y]}function No(n){return function(){var t=n.apply(this,arguments),e=t[0],r=t[1]+ms;return[e*Math.cos(r),e*Math.sin(r)]}}function zo(){return 64}function Lo(){return"circle"}function To(n){var t=Math.sqrt(n/ba);return"M0,"+t+"A"+t+","+t+" 0 1,1 0,"+-t+"A"+t+","+t+" 0 1,1 0,"+t+"Z"}function qo(n,t){return sa(n,Cs),n.id=t,n}function Ro(n,t,e,r){var u=n.id;return P(n,"function"==typeof e?function(n,i,o){n.__transition__[u].tween.set(t,r(e.call(n,n.__data__,i,o)))}:(e=r(e),function(n){n.__transition__[u].tween.set(t,e)}))}function Do(n){return null==n&&(n=""),function(){this.textContent=n}}function Po(n,t,e,r){var u=n.__transition__||(n.__transition__={active:0,count:0}),i=u[e];if(!i){var a=r.time;i=u[e]={tween:new o,time:a,ease:r.ease,delay:r.delay,duration:r.duration},++u.count,Zo.timer(function(r){function o(r){return u.active>e?s():(u.active=e,i.event&&i.event.start.call(n,l,t),i.tween.forEach(function(e,r){(r=r.call(n,l,t))&&v.push(r)}),Zo.timer(function(){return p.c=c(r||1)?we:c,1},0,a),void 0)}function c(r){if(u.active!==e)return s();for(var o=r/g,a=f(o),c=v.length;c>0;)v[--c].call(n,a);
+return o>=1?(i.event&&i.event.end.call(n,l,t),s()):void 0}function s(){return--u.count?delete u[e]:delete n.__transition__,1}var l=n.__data__,f=i.ease,h=i.delay,g=i.duration,p=Ba,v=[];return p.t=h+a,r>=h?o(r-h):(p.c=o,void 0)},0,a)}}function Uo(n,t){n.attr("transform",function(n){return"translate("+t(n)+",0)"})}function jo(n,t){n.attr("transform",function(n){return"translate(0,"+t(n)+")"})}function Ho(n){return n.toISOString()}function Fo(n,t,e){function r(t){return n(t)}function u(n,e){var r=n[1]-n[0],u=r/e,i=Zo.bisect(Us,u);return i==Us.length?[t.year,Fi(n.map(function(n){return n/31536e6}),e)[2]]:i?t[u/Us[i-1]<Us[i]/u?i-1:i]:[Fs,Fi(n,e)[2]]}return r.invert=function(t){return Oo(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain(t),r):n.domain().map(Oo)},r.nice=function(n,t){function e(e){return!isNaN(e)&&!n.range(e,Oo(+e+1),t).length}var i=r.domain(),o=Li(i),a=null==n?u(o,10):"number"==typeof n&&u(o,n);return a&&(n=a[0],t=a[1]),r.domain(Ri(i,t>1?{floor:function(t){for(;e(t=n.floor(t));)t=Oo(t-1);return t},ceil:function(t){for(;e(t=n.ceil(t));)t=Oo(+t+1);return t}}:n))},r.ticks=function(n,t){var e=Li(r.domain()),i=null==n?u(e,10):"number"==typeof n?u(e,n):!n.range&&[{range:n},t];return i&&(n=i[0],t=i[1]),n.range(e[0],Oo(+e[1]+1),1>t?1:t)},r.tickFormat=function(){return e},r.copy=function(){return Fo(n.copy(),t,e)},ji(r,n)}function Oo(n){return new Date(n)}function Yo(n){return JSON.parse(n.responseText)}function Io(n){var t=$o.createRange();return t.selectNode($o.body),t.createContextualFragment(n.responseText)}var Zo={version:"3.4.11"};Date.now||(Date.now=function(){return+new Date});var Vo=[].slice,Xo=function(n){return Vo.call(n)},$o=document,Bo=$o.documentElement,Wo=window;try{Xo(Bo.childNodes)[0].nodeType}catch(Jo){Xo=function(n){for(var t=n.length,e=new Array(t);t--;)e[t]=n[t];return e}}try{$o.createElement("div").style.setProperty("opacity",0,"")}catch(Go){var Ko=Wo.Element.prototype,Qo=Ko.setAttribute,na=Ko.setAttributeNS,ta=Wo.CSSStyleDeclaration.prototype,ea=ta.setProperty;Ko.setAttribute=function(n,t){Qo.call(this,n,t+"")},Ko.setAttributeNS=function(n,t,e){na.call(this,n,t,e+"")},ta.setProperty=function(n,t,e){ea.call(this,n,t+"",e)}}Zo.ascending=n,Zo.descending=function(n,t){return n>t?-1:t>n?1:t>=n?0:0/0},Zo.min=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u<i&&!(null!=(e=n[u])&&e>=e);)e=void 0;for(;++u<i;)null!=(r=n[u])&&e>r&&(e=r)}else{for(;++u<i&&!(null!=(e=t.call(n,n[u],u))&&e>=e);)e=void 0;for(;++u<i;)null!=(r=t.call(n,n[u],u))&&e>r&&(e=r)}return e},Zo.max=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u<i&&!(null!=(e=n[u])&&e>=e);)e=void 0;for(;++u<i;)null!=(r=n[u])&&r>e&&(e=r)}else{for(;++u<i&&!(null!=(e=t.call(n,n[u],u))&&e>=e);)e=void 0;for(;++u<i;)null!=(r=t.call(n,n[u],u))&&r>e&&(e=r)}return e},Zo.extent=function(n,t){var e,r,u,i=-1,o=n.length;if(1===arguments.length){for(;++i<o&&!(null!=(e=u=n[i])&&e>=e);)e=u=void 0;for(;++i<o;)null!=(r=n[i])&&(e>r&&(e=r),r>u&&(u=r))}else{for(;++i<o&&!(null!=(e=u=t.call(n,n[i],i))&&e>=e);)e=void 0;for(;++i<o;)null!=(r=t.call(n,n[i],i))&&(e>r&&(e=r),r>u&&(u=r))}return[e,u]},Zo.sum=function(n,t){var e,r=0,u=n.length,i=-1;if(1===arguments.length)for(;++i<u;)isNaN(e=+n[i])||(r+=e);else for(;++i<u;)isNaN(e=+t.call(n,n[i],i))||(r+=e);return r},Zo.mean=function(n,e){var r,u=0,i=n.length,o=-1,a=i;if(1===arguments.length)for(;++o<i;)t(r=n[o])?u+=r:--a;else for(;++o<i;)t(r=e.call(n,n[o],o))?u+=r:--a;return a?u/a:void 0},Zo.quantile=function(n,t){var e=(n.length-1)*t+1,r=Math.floor(e),u=+n[r-1],i=e-r;return i?u+i*(n[r]-u):u},Zo.median=function(e,r){return arguments.length>1&&(e=e.map(r)),e=e.filter(t),e.length?Zo.quantile(e.sort(n),.5):void 0};var ra=e(n);Zo.bisectLeft=ra.left,Zo.bisect=Zo.bisectRight=ra.right,Zo.bisector=function(t){return e(1===t.length?function(e,r){return n(t(e),r)}:t)},Zo.shuffle=function(n){for(var t,e,r=n.length;r;)e=0|Math.random()*r--,t=n[r],n[r]=n[e],n[e]=t;return n},Zo.permute=function(n,t){for(var e=t.length,r=new Array(e);e--;)r[e]=n[t[e]];return r},Zo.pairs=function(n){for(var t,e=0,r=n.length-1,u=n[0],i=new Array(0>r?0:r);r>e;)i[e]=[t=u,u=n[++e]];return i},Zo.zip=function(){if(!(u=arguments.length))return[];for(var n=-1,t=Zo.min(arguments,r),e=new Array(t);++n<t;)for(var u,i=-1,o=e[n]=new Array(u);++i<u;)o[i]=arguments[i][n];return e},Zo.transpose=function(n){return Zo.zip.apply(Zo,n)},Zo.keys=function(n){var t=[];for(var e in n)t.push(e);return t},Zo.values=function(n){var t=[];for(var e in n)t.push(n[e]);return t},Zo.entries=function(n){var t=[];for(var e in n)t.push({key:e,value:n[e]});return t},Zo.merge=function(n){for(var t,e,r,u=n.length,i=-1,o=0;++i<u;)o+=n[i].length;for(e=new Array(o);--u>=0;)for(r=n[u],t=r.length;--t>=0;)e[--o]=r[t];return e};var ua=Math.abs;Zo.range=function(n,t,e){if(arguments.length<3&&(e=1,arguments.length<2&&(t=n,n=0)),1/0===(t-n)/e)throw new Error("infinite range");var r,i=[],o=u(ua(e)),a=-1;if(n*=o,t*=o,e*=o,0>e)for(;(r=n+e*++a)>t;)i.push(r/o);else for(;(r=n+e*++a)<t;)i.push(r/o);return i},Zo.map=function(n){var t=new o;if(n instanceof o)n.forEach(function(n,e){t.set(n,e)});else for(var e in n)t.set(e,n[e]);return t},i(o,{has:a,get:function(n){return this[ia+n]},set:function(n,t){return this[ia+n]=t},remove:c,keys:s,values:function(){var n=[];return this.forEach(function(t,e){n.push(e)}),n},entries:function(){var n=[];return this.forEach(function(t,e){n.push({key:t,value:e})}),n},size:l,empty:f,forEach:function(n){for(var t in this)t.charCodeAt(0)===oa&&n.call(this,t.substring(1),this[t])}});var ia="\x00",oa=ia.charCodeAt(0);Zo.nest=function(){function n(t,a,c){if(c>=i.length)return r?r.call(u,a):e?a.sort(e):a;for(var s,l,f,h,g=-1,p=a.length,v=i[c++],d=new o;++g<p;)(h=d.get(s=v(l=a[g])))?h.push(l):d.set(s,[l]);return t?(l=t(),f=function(e,r){l.set(e,n(t,r,c))}):(l={},f=function(e,r){l[e]=n(t,r,c)}),d.forEach(f),l}function t(n,e){if(e>=i.length)return n;var r=[],u=a[e++];return n.forEach(function(n,u){r.push({key:n,values:t(u,e)})}),u?r.sort(function(n,t){return u(n.key,t.key)}):r}var e,r,u={},i=[],a=[];return u.map=function(t,e){return n(e,t,0)},u.entries=function(e){return t(n(Zo.map,e,0),0)},u.key=function(n){return i.push(n),u},u.sortKeys=function(n){return a[i.length-1]=n,u},u.sortValues=function(n){return e=n,u},u.rollup=function(n){return r=n,u},u},Zo.set=function(n){var t=new h;if(n)for(var e=0,r=n.length;r>e;++e)t.add(n[e]);return t},i(h,{has:a,add:function(n){return this[ia+n]=!0,n},remove:function(n){return n=ia+n,n in this&&delete this[n]},values:s,size:l,empty:f,forEach:function(n){for(var t in this)t.charCodeAt(0)===oa&&n.call(this,t.substring(1))}}),Zo.behavior={},Zo.rebind=function(n,t){for(var e,r=1,u=arguments.length;++r<u;)n[e=arguments[r]]=g(n,t,t[e]);return n};var aa=["webkit","ms","moz","Moz","o","O"];Zo.dispatch=function(){for(var n=new d,t=-1,e=arguments.length;++t<e;)n[arguments[t]]=m(n);return n},d.prototype.on=function(n,t){var e=n.indexOf("."),r="";if(e>=0&&(r=n.substring(e+1),n=n.substring(0,e)),n)return arguments.length<2?this[n].on(r):this[n].on(r,t);if(2===arguments.length){if(null==t)for(n in this)this.hasOwnProperty(n)&&this[n].on(r,null);return this}},Zo.event=null,Zo.requote=function(n){return n.replace(ca,"\\$&")};var ca=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,sa={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var e in t)n[e]=t[e]},la=function(n,t){return t.querySelector(n)},fa=function(n,t){return t.querySelectorAll(n)},ha=Bo.matches||Bo[p(Bo,"matchesSelector")],ga=function(n,t){return ha.call(n,t)};"function"==typeof Sizzle&&(la=function(n,t){return Sizzle(n,t)[0]||null},fa=Sizzle,ga=Sizzle.matchesSelector),Zo.selection=function(){return ma};var pa=Zo.selection.prototype=[];pa.select=function(n){var t,e,r,u,i=[];n=b(n);for(var o=-1,a=this.length;++o<a;){i.push(t=[]),t.parentNode=(r=this[o]).parentNode;for(var c=-1,s=r.length;++c<s;)(u=r[c])?(t.push(e=n.call(u,u.__data__,c,o)),e&&"__data__"in u&&(e.__data__=u.__data__)):t.push(null)}return _(i)},pa.selectAll=function(n){var t,e,r=[];n=w(n);for(var u=-1,i=this.length;++u<i;)for(var o=this[u],a=-1,c=o.length;++a<c;)(e=o[a])&&(r.push(t=Xo(n.call(e,e.__data__,a,u))),t.parentNode=e);return _(r)};var va={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};Zo.ns={prefix:va,qualify:function(n){var t=n.indexOf(":"),e=n;return t>=0&&(e=n.substring(0,t),n=n.substring(t+1)),va.hasOwnProperty(e)?{space:va[e],local:n}:n}},pa.attr=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node();return n=Zo.ns.qualify(n),n.local?e.getAttributeNS(n.space,n.local):e.getAttribute(n)}for(t in n)this.each(S(t,n[t]));return this}return this.each(S(n,t))},pa.classed=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node(),r=(n=A(n)).length,u=-1;if(t=e.classList){for(;++u<r;)if(!t.contains(n[u]))return!1}else for(t=e.getAttribute("class");++u<r;)if(!E(n[u]).test(t))return!1;return!0}for(t in n)this.each(C(t,n[t]));return this}return this.each(C(n,t))},pa.style=function(n,t,e){var r=arguments.length;if(3>r){if("string"!=typeof n){2>r&&(t="");for(e in n)this.each(z(e,n[e],t));return this}if(2>r)return Wo.getComputedStyle(this.node(),null).getPropertyValue(n);e=""}return this.each(z(n,t,e))},pa.property=function(n,t){if(arguments.length<2){if("string"==typeof n)return this.node()[n];for(t in n)this.each(L(t,n[t]));return this}return this.each(L(n,t))},pa.text=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.textContent=null==t?"":t}:null==n?function(){this.textContent=""}:function(){this.textContent=n}):this.node().textContent},pa.html=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.innerHTML=null==t?"":t}:null==n?function(){this.innerHTML=""}:function(){this.innerHTML=n}):this.node().innerHTML},pa.append=function(n){return n=T(n),this.select(function(){return this.appendChild(n.apply(this,arguments))})},pa.insert=function(n,t){return n=T(n),t=b(t),this.select(function(){return this.insertBefore(n.apply(this,arguments),t.apply(this,arguments)||null)})},pa.remove=function(){return this.each(function(){var n=this.parentNode;n&&n.removeChild(this)})},pa.data=function(n,t){function e(n,e){var r,u,i,a=n.length,f=e.length,h=Math.min(a,f),g=new Array(f),p=new Array(f),v=new Array(a);if(t){var d,m=new o,y=new o,x=[];for(r=-1;++r<a;)d=t.call(u=n[r],u.__data__,r),m.has(d)?v[r]=u:m.set(d,u),x.push(d);for(r=-1;++r<f;)d=t.call(e,i=e[r],r),(u=m.get(d))?(g[r]=u,u.__data__=i):y.has(d)||(p[r]=q(i)),y.set(d,i),m.remove(d);for(r=-1;++r<a;)m.has(x[r])&&(v[r]=n[r])}else{for(r=-1;++r<h;)u=n[r],i=e[r],u?(u.__data__=i,g[r]=u):p[r]=q(i);for(;f>r;++r)p[r]=q(e[r]);for(;a>r;++r)v[r]=n[r]}p.update=g,p.parentNode=g.parentNode=v.parentNode=n.parentNode,c.push(p),s.push(g),l.push(v)}var r,u,i=-1,a=this.length;if(!arguments.length){for(n=new Array(a=(r=this[0]).length);++i<a;)(u=r[i])&&(n[i]=u.__data__);return n}var c=U([]),s=_([]),l=_([]);if("function"==typeof n)for(;++i<a;)e(r=this[i],n.call(r,r.parentNode.__data__,i));else for(;++i<a;)e(r=this[i],n);return s.enter=function(){return c},s.exit=function(){return l},s},pa.datum=function(n){return arguments.length?this.property("__data__",n):this.property("__data__")},pa.filter=function(n){var t,e,r,u=[];"function"!=typeof n&&(n=R(n));for(var i=0,o=this.length;o>i;i++){u.push(t=[]),t.parentNode=(e=this[i]).parentNode;for(var a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return _(u)},pa.order=function(){for(var n=-1,t=this.length;++n<t;)for(var e,r=this[n],u=r.length-1,i=r[u];--u>=0;)(e=r[u])&&(i&&i!==e.nextSibling&&i.parentNode.insertBefore(e,i),i=e);return this},pa.sort=function(n){n=D.apply(this,arguments);for(var t=-1,e=this.length;++t<e;)this[t].sort(n);return this.order()},pa.each=function(n){return P(this,function(t,e,r){n.call(t,t.__data__,e,r)})},pa.call=function(n){var t=Xo(arguments);return n.apply(t[0]=this,t),this},pa.empty=function(){return!this.node()},pa.node=function(){for(var n=0,t=this.length;t>n;n++)for(var e=this[n],r=0,u=e.length;u>r;r++){var i=e[r];if(i)return i}return null},pa.size=function(){var n=0;return this.each(function(){++n}),n};var da=[];Zo.selection.enter=U,Zo.selection.enter.prototype=da,da.append=pa.append,da.empty=pa.empty,da.node=pa.node,da.call=pa.call,da.size=pa.size,da.select=function(n){for(var t,e,r,u,i,o=[],a=-1,c=this.length;++a<c;){r=(u=this[a]).update,o.push(t=[]),t.parentNode=u.parentNode;for(var s=-1,l=u.length;++s<l;)(i=u[s])?(t.push(r[s]=e=n.call(u.parentNode,i.__data__,s,a)),e.__data__=i.__data__):t.push(null)}return _(o)},da.insert=function(n,t){return arguments.length<2&&(t=j(this)),pa.insert.call(this,n,t)},pa.transition=function(){for(var n,t,e=Ss||++Ns,r=[],u=ks||{time:Date.now(),ease:xu,delay:0,duration:250},i=-1,o=this.length;++i<o;){r.push(n=[]);for(var a=this[i],c=-1,s=a.length;++c<s;)(t=a[c])&&Po(t,c,e,u),n.push(t)}return qo(r,e)},pa.interrupt=function(){return this.each(H)},Zo.select=function(n){var t=["string"==typeof n?la(n,$o):n];return t.parentNode=Bo,_([t])},Zo.selectAll=function(n){var t=Xo("string"==typeof n?fa(n,$o):n);return t.parentNode=Bo,_([t])};var ma=Zo.select(Bo);pa.on=function(n,t,e){var r=arguments.length;if(3>r){if("string"!=typeof n){2>r&&(t=!1);for(e in n)this.each(F(e,n[e],t));return this}if(2>r)return(r=this.node()["__on"+n])&&r._;e=!1}return this.each(F(n,t,e))};var ya=Zo.map({mouseenter:"mouseover",mouseleave:"mouseout"});ya.forEach(function(n){"on"+n in $o&&ya.remove(n)});var xa="onselectstart"in $o?null:p(Bo.style,"userSelect"),Ma=0;Zo.mouse=function(n){return Z(n,x())};var _a=/WebKit/.test(Wo.navigator.userAgent)?-1:0;Zo.touches=function(n,t){return arguments.length<2&&(t=x().touches),t?Xo(t).map(function(t){var e=Z(n,t);return e.identifier=t.identifier,e}):[]},Zo.behavior.drag=function(){function n(){this.on("mousedown.drag",u).on("touchstart.drag",i)}function t(n,t,u,i,o){return function(){function a(){var n,e,r=t(h,v);r&&(n=r[0]-x[0],e=r[1]-x[1],p|=n|e,x=r,g({type:"drag",x:r[0]+s[0],y:r[1]+s[1],dx:n,dy:e}))}function c(){t(h,v)&&(m.on(i+d,null).on(o+d,null),y(p&&Zo.event.target===f),g({type:"dragend"}))}var s,l=this,f=Zo.event.target,h=l.parentNode,g=e.of(l,arguments),p=0,v=n(),d=".drag"+(null==v?"":"-"+v),m=Zo.select(u()).on(i+d,a).on(o+d,c),y=I(),x=t(h,v);r?(s=r.apply(l,arguments),s=[s.x-x[0],s.y-x[1]]):s=[0,0],g({type:"dragstart"})}}var e=M(n,"drag","dragstart","dragend"),r=null,u=t(v,Zo.mouse,$,"mousemove","mouseup"),i=t(V,Zo.touch,X,"touchmove","touchend");return n.origin=function(t){return arguments.length?(r=t,n):r},Zo.rebind(n,e,"on")};var ba=Math.PI,wa=2*ba,Sa=ba/2,ka=1e-6,Ea=ka*ka,Aa=ba/180,Ca=180/ba,Na=Math.SQRT2,za=2,La=4;Zo.interpolateZoom=function(n,t){function e(n){var t=n*y;if(m){var e=Q(v),o=i/(za*h)*(e*nt(Na*t+v)-K(v));return[r+o*s,u+o*l,i*e/Q(Na*t+v)]}return[r+n*s,u+n*l,i*Math.exp(Na*t)]}var r=n[0],u=n[1],i=n[2],o=t[0],a=t[1],c=t[2],s=o-r,l=a-u,f=s*s+l*l,h=Math.sqrt(f),g=(c*c-i*i+La*f)/(2*i*za*h),p=(c*c-i*i-La*f)/(2*c*za*h),v=Math.log(Math.sqrt(g*g+1)-g),d=Math.log(Math.sqrt(p*p+1)-p),m=d-v,y=(m||Math.log(c/i))/Na;return e.duration=1e3*y,e},Zo.behavior.zoom=function(){function n(n){n.on(A,s).on(Ra+".zoom",f).on("dblclick.zoom",h).on(z,l)}function t(n){return[(n[0]-S.x)/S.k,(n[1]-S.y)/S.k]}function e(n){return[n[0]*S.k+S.x,n[1]*S.k+S.y]}function r(n){S.k=Math.max(E[0],Math.min(E[1],n))}function u(n,t){t=e(t),S.x+=n[0]-t[0],S.y+=n[1]-t[1]}function i(){_&&_.domain(x.range().map(function(n){return(n-S.x)/S.k}).map(x.invert)),w&&w.domain(b.range().map(function(n){return(n-S.y)/S.k}).map(b.invert))}function o(n){n({type:"zoomstart"})}function a(n){i(),n({type:"zoom",scale:S.k,translate:[S.x,S.y]})}function c(n){n({type:"zoomend"})}function s(){function n(){l=1,u(Zo.mouse(r),h),a(s)}function e(){f.on(C,null).on(N,null),g(l&&Zo.event.target===i),c(s)}var r=this,i=Zo.event.target,s=L.of(r,arguments),l=0,f=Zo.select(Wo).on(C,n).on(N,e),h=t(Zo.mouse(r)),g=I();H.call(r),o(s)}function l(){function n(){var n=Zo.touches(g);return h=S.k,n.forEach(function(n){n.identifier in v&&(v[n.identifier]=t(n))}),n}function e(){var t=Zo.event.target;Zo.select(t).on(M,i).on(_,f),b.push(t);for(var e=Zo.event.changedTouches,o=0,c=e.length;c>o;++o)v[e[o].identifier]=null;var s=n(),l=Date.now();if(1===s.length){if(500>l-m){var h=s[0],g=v[h.identifier];r(2*S.k),u(h,g),y(),a(p)}m=l}else if(s.length>1){var h=s[0],x=s[1],w=h[0]-x[0],k=h[1]-x[1];d=w*w+k*k}}function i(){for(var n,t,e,i,o=Zo.touches(g),c=0,s=o.length;s>c;++c,i=null)if(e=o[c],i=v[e.identifier]){if(t)break;n=e,t=i}if(i){var l=(l=e[0]-n[0])*l+(l=e[1]-n[1])*l,f=d&&Math.sqrt(l/d);n=[(n[0]+e[0])/2,(n[1]+e[1])/2],t=[(t[0]+i[0])/2,(t[1]+i[1])/2],r(f*h)}m=null,u(n,t),a(p)}function f(){if(Zo.event.touches.length){for(var t=Zo.event.changedTouches,e=0,r=t.length;r>e;++e)delete v[t[e].identifier];for(var u in v)return void n()}Zo.selectAll(b).on(x,null),w.on(A,s).on(z,l),k(),c(p)}var h,g=this,p=L.of(g,arguments),v={},d=0,x=".zoom-"+Zo.event.changedTouches[0].identifier,M="touchmove"+x,_="touchend"+x,b=[],w=Zo.select(g).on(A,null).on(z,e),k=I();H.call(g),e(),o(p)}function f(){var n=L.of(this,arguments);d?clearTimeout(d):(g=t(p=v||Zo.mouse(this)),H.call(this),o(n)),d=setTimeout(function(){d=null,c(n)},50),y(),r(Math.pow(2,.002*Ta())*S.k),u(p,g),a(n)}function h(){var n=L.of(this,arguments),e=Zo.mouse(this),i=t(e),s=Math.log(S.k)/Math.LN2;o(n),r(Math.pow(2,Zo.event.shiftKey?Math.ceil(s)-1:Math.floor(s)+1)),u(e,i),a(n),c(n)}var g,p,v,d,m,x,_,b,w,S={x:0,y:0,k:1},k=[960,500],E=qa,A="mousedown.zoom",C="mousemove.zoom",N="mouseup.zoom",z="touchstart.zoom",L=M(n,"zoomstart","zoom","zoomend");return n.event=function(n){n.each(function(){var n=L.of(this,arguments),t=S;Ss?Zo.select(this).transition().each("start.zoom",function(){S=this.__chart__||{x:0,y:0,k:1},o(n)}).tween("zoom:zoom",function(){var e=k[0],r=k[1],u=e/2,i=r/2,o=Zo.interpolateZoom([(u-S.x)/S.k,(i-S.y)/S.k,e/S.k],[(u-t.x)/t.k,(i-t.y)/t.k,e/t.k]);return function(t){var r=o(t),c=e/r[2];this.__chart__=S={x:u-r[0]*c,y:i-r[1]*c,k:c},a(n)}}).each("end.zoom",function(){c(n)}):(this.__chart__=S,o(n),a(n),c(n))})},n.translate=function(t){return arguments.length?(S={x:+t[0],y:+t[1],k:S.k},i(),n):[S.x,S.y]},n.scale=function(t){return arguments.length?(S={x:S.x,y:S.y,k:+t},i(),n):S.k},n.scaleExtent=function(t){return arguments.length?(E=null==t?qa:[+t[0],+t[1]],n):E},n.center=function(t){return arguments.length?(v=t&&[+t[0],+t[1]],n):v},n.size=function(t){return arguments.length?(k=t&&[+t[0],+t[1]],n):k},n.x=function(t){return arguments.length?(_=t,x=t.copy(),S={x:0,y:0,k:1},n):_},n.y=function(t){return arguments.length?(w=t,b=t.copy(),S={x:0,y:0,k:1},n):w},Zo.rebind(n,L,"on")};var Ta,qa=[0,1/0],Ra="onwheel"in $o?(Ta=function(){return-Zo.event.deltaY*(Zo.event.deltaMode?120:1)},"wheel"):"onmousewheel"in $o?(Ta=function(){return Zo.event.wheelDelta},"mousewheel"):(Ta=function(){return-Zo.event.detail},"MozMousePixelScroll");Zo.color=et,et.prototype.toString=function(){return this.rgb()+""},Zo.hsl=rt;var Da=rt.prototype=new et;Da.brighter=function(n){return n=Math.pow(.7,arguments.length?n:1),new rt(this.h,this.s,this.l/n)},Da.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new rt(this.h,this.s,n*this.l)},Da.rgb=function(){return ut(this.h,this.s,this.l)},Zo.hcl=it;var Pa=it.prototype=new et;Pa.brighter=function(n){return new it(this.h,this.c,Math.min(100,this.l+Ua*(arguments.length?n:1)))},Pa.darker=function(n){return new it(this.h,this.c,Math.max(0,this.l-Ua*(arguments.length?n:1)))},Pa.rgb=function(){return ot(this.h,this.c,this.l).rgb()},Zo.lab=at;var Ua=18,ja=.95047,Ha=1,Fa=1.08883,Oa=at.prototype=new et;Oa.brighter=function(n){return new at(Math.min(100,this.l+Ua*(arguments.length?n:1)),this.a,this.b)},Oa.darker=function(n){return new at(Math.max(0,this.l-Ua*(arguments.length?n:1)),this.a,this.b)},Oa.rgb=function(){return ct(this.l,this.a,this.b)},Zo.rgb=gt;var Ya=gt.prototype=new et;Ya.brighter=function(n){n=Math.pow(.7,arguments.length?n:1);var t=this.r,e=this.g,r=this.b,u=30;return t||e||r?(t&&u>t&&(t=u),e&&u>e&&(e=u),r&&u>r&&(r=u),new gt(Math.min(255,t/n),Math.min(255,e/n),Math.min(255,r/n))):new gt(u,u,u)},Ya.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new gt(n*this.r,n*this.g,n*this.b)},Ya.hsl=function(){return yt(this.r,this.g,this.b)},Ya.toString=function(){return"#"+dt(this.r)+dt(this.g)+dt(this.b)};var Ia=Zo.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});Ia.forEach(function(n,t){Ia.set(n,pt(t))}),Zo.functor=bt,Zo.xhr=St(wt),Zo.dsv=function(n,t){function e(n,e,i){arguments.length<3&&(i=e,e=null);var o=kt(n,t,null==e?r:u(e),i);return o.row=function(n){return arguments.length?o.response(null==(e=n)?r:u(n)):e},o}function r(n){return e.parse(n.responseText)}function u(n){return function(t){return e.parse(t.responseText,n)}}function i(t){return t.map(o).join(n)}function o(n){return a.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}var a=new RegExp('["'+n+"\n]"),c=n.charCodeAt(0);return e.parse=function(n,t){var r;return e.parseRows(n,function(n,e){if(r)return r(n,e-1);var u=new Function("d","return {"+n.map(function(n,t){return JSON.stringify(n)+": d["+t+"]"}).join(",")+"}");r=t?function(n,e){return t(u(n),e)}:u})},e.parseRows=function(n,t){function e(){if(l>=s)return o;if(u)return u=!1,i;var t=l;if(34===n.charCodeAt(t)){for(var e=t;e++<s;)if(34===n.charCodeAt(e)){if(34!==n.charCodeAt(e+1))break;++e}l=e+2;var r=n.charCodeAt(e+1);return 13===r?(u=!0,10===n.charCodeAt(e+2)&&++l):10===r&&(u=!0),n.substring(t+1,e).replace(/""/g,'"')}for(;s>l;){var r=n.charCodeAt(l++),a=1;if(10===r)u=!0;else if(13===r)u=!0,10===n.charCodeAt(l)&&(++l,++a);else if(r!==c)continue;return n.substring(t,l-a)}return n.substring(t)}for(var r,u,i={},o={},a=[],s=n.length,l=0,f=0;(r=e())!==o;){for(var h=[];r!==i&&r!==o;)h.push(r),r=e();(!t||(h=t(h,f++)))&&a.push(h)}return a},e.format=function(t){if(Array.isArray(t[0]))return e.formatRows(t);var r=new h,u=[];return t.forEach(function(n){for(var t in n)r.has(t)||u.push(r.add(t))}),[u.map(o).join(n)].concat(t.map(function(t){return u.map(function(n){return o(t[n])}).join(n)})).join("\n")},e.formatRows=function(n){return n.map(i).join("\n")},e},Zo.csv=Zo.dsv(",","text/csv"),Zo.tsv=Zo.dsv(" ","text/tab-separated-values"),Zo.touch=function(n,t,e){if(arguments.length<3&&(e=t,t=x().changedTouches),t)for(var r,u=0,i=t.length;i>u;++u)if((r=t[u]).identifier===e)return Z(n,r)};var Za,Va,Xa,$a,Ba,Wa=Wo[p(Wo,"requestAnimationFrame")]||function(n){setTimeout(n,17)};Zo.timer=function(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now());var u=e+t,i={c:n,t:u,f:!1,n:null};Va?Va.n=i:Za=i,Va=i,Xa||($a=clearTimeout($a),Xa=1,Wa(At))},Zo.timer.flush=function(){Ct(),Nt()},Zo.round=function(n,t){return t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)};var Ja=["y","z","a","f","p","n","\xb5","m","","k","M","G","T","P","E","Z","Y"].map(Lt);Zo.formatPrefix=function(n,t){var e=0;return n&&(0>n&&(n*=-1),t&&(n=Zo.round(n,zt(n,t))),e=1+Math.floor(1e-12+Math.log(n)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((e-1)/3)))),Ja[8+e/3]};var Ga=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,Ka=Zo.map({b:function(n){return n.toString(2)},c:function(n){return String.fromCharCode(n)},o:function(n){return n.toString(8)},x:function(n){return n.toString(16)},X:function(n){return n.toString(16).toUpperCase()},g:function(n,t){return n.toPrecision(t)},e:function(n,t){return n.toExponential(t)},f:function(n,t){return n.toFixed(t)},r:function(n,t){return(n=Zo.round(n,zt(n,t))).toFixed(Math.max(0,Math.min(20,zt(n*(1+1e-15),t))))}}),Qa=Zo.time={},nc=Date;Rt.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){tc.setUTCDate.apply(this._,arguments)},setDay:function(){tc.setUTCDay.apply(this._,arguments)},setFullYear:function(){tc.setUTCFullYear.apply(this._,arguments)},setHours:function(){tc.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){tc.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){tc.setUTCMinutes.apply(this._,arguments)},setMonth:function(){tc.setUTCMonth.apply(this._,arguments)},setSeconds:function(){tc.setUTCSeconds.apply(this._,arguments)},setTime:function(){tc.setTime.apply(this._,arguments)}};var tc=Date.prototype;Qa.year=Dt(function(n){return n=Qa.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return n.getFullYear()}),Qa.years=Qa.year.range,Qa.years.utc=Qa.year.utc.range,Qa.day=Dt(function(n){var t=new nc(2e3,0);return t.setFullYear(n.getFullYear(),n.getMonth(),n.getDate()),t},function(n,t){n.setDate(n.getDate()+t)},function(n){return n.getDate()-1}),Qa.days=Qa.day.range,Qa.days.utc=Qa.day.utc.range,Qa.dayOfYear=function(n){var t=Qa.year(n);return Math.floor((n-t-6e4*(n.getTimezoneOffset()-t.getTimezoneOffset()))/864e5)},["sunday","monday","tuesday","wednesday","thursday","friday","saturday"].forEach(function(n,t){t=7-t;var e=Qa[n]=Dt(function(n){return(n=Qa.day(n)).setDate(n.getDate()-(n.getDay()+t)%7),n},function(n,t){n.setDate(n.getDate()+7*Math.floor(t))},function(n){var e=Qa.year(n).getDay();return Math.floor((Qa.dayOfYear(n)+(e+t)%7)/7)-(e!==t)});Qa[n+"s"]=e.range,Qa[n+"s"].utc=e.utc.range,Qa[n+"OfYear"]=function(n){var e=Qa.year(n).getDay();return Math.floor((Qa.dayOfYear(n)+(e+t)%7)/7)}}),Qa.week=Qa.sunday,Qa.weeks=Qa.sunday.range,Qa.weeks.utc=Qa.sunday.utc.range,Qa.weekOfYear=Qa.sundayOfYear;var ec={"-":"",_:" ",0:"0"},rc=/^\s*\d+/,uc=/^%/;Zo.locale=function(n){return{numberFormat:Tt(n),timeFormat:Ut(n)}};var ic=Zo.locale({decimal:".",thousands:",",grouping:[3],currency:["$",""],dateTime:"%a %b %e %X %Y",date:"%m/%d/%Y",time:"%H:%M:%S",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});Zo.format=ic.numberFormat,Zo.geo={},ue.prototype={s:0,t:0,add:function(n){ie(n,this.t,oc),ie(oc.s,this.s,this),this.s?this.t+=oc.t:this.s=oc.t},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var oc=new ue;Zo.geo.stream=function(n,t){n&&ac.hasOwnProperty(n.type)?ac[n.type](n,t):oe(n,t)};var ac={Feature:function(n,t){oe(n.geometry,t)},FeatureCollection:function(n,t){for(var e=n.features,r=-1,u=e.length;++r<u;)oe(e[r].geometry,t)}},cc={Sphere:function(n,t){t.sphere()},Point:function(n,t){n=n.coordinates,t.point(n[0],n[1],n[2])},MultiPoint:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)n=e[r],t.point(n[0],n[1],n[2])},LineString:function(n,t){ae(n.coordinates,t,0)},MultiLineString:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)ae(e[r],t,0)},Polygon:function(n,t){ce(n.coordinates,t)},MultiPolygon:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)ce(e[r],t)},GeometryCollection:function(n,t){for(var e=n.geometries,r=-1,u=e.length;++r<u;)oe(e[r],t)}};Zo.geo.area=function(n){return sc=0,Zo.geo.stream(n,fc),sc};var sc,lc=new ue,fc={sphere:function(){sc+=4*ba},point:v,lineStart:v,lineEnd:v,polygonStart:function(){lc.reset(),fc.lineStart=se},polygonEnd:function(){var n=2*lc;sc+=0>n?4*ba+n:n,fc.lineStart=fc.lineEnd=fc.point=v}};Zo.geo.bounds=function(){function n(n,t){x.push(M=[l=n,h=n]),f>t&&(f=t),t>g&&(g=t)}function t(t,e){var r=le([t*Aa,e*Aa]);if(m){var u=he(m,r),i=[u[1],-u[0],0],o=he(i,u);ve(o),o=de(o);var c=t-p,s=c>0?1:-1,v=o[0]*Ca*s,d=ua(c)>180;if(d^(v>s*p&&s*t>v)){var y=o[1]*Ca;y>g&&(g=y)}else if(v=(v+360)%360-180,d^(v>s*p&&s*t>v)){var y=-o[1]*Ca;f>y&&(f=y)}else f>e&&(f=e),e>g&&(g=e);d?p>t?a(l,t)>a(l,h)&&(h=t):a(t,h)>a(l,h)&&(l=t):h>=l?(l>t&&(l=t),t>h&&(h=t)):t>p?a(l,t)>a(l,h)&&(h=t):a(t,h)>a(l,h)&&(l=t)}else n(t,e);m=r,p=t}function e(){_.point=t}function r(){M[0]=l,M[1]=h,_.point=n,m=null}function u(n,e){if(m){var r=n-p;y+=ua(r)>180?r+(r>0?360:-360):r}else v=n,d=e;fc.point(n,e),t(n,e)}function i(){fc.lineStart()}function o(){u(v,d),fc.lineEnd(),ua(y)>ka&&(l=-(h=180)),M[0]=l,M[1]=h,m=null}function a(n,t){return(t-=n)<0?t+360:t}function c(n,t){return n[0]-t[0]}function s(n,t){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var l,f,h,g,p,v,d,m,y,x,M,_={point:n,lineStart:e,lineEnd:r,polygonStart:function(){_.point=u,_.lineStart=i,_.lineEnd=o,y=0,fc.polygonStart()},polygonEnd:function(){fc.polygonEnd(),_.point=n,_.lineStart=e,_.lineEnd=r,0>lc?(l=-(h=180),f=-(g=90)):y>ka?g=90:-ka>y&&(f=-90),M[0]=l,M[1]=h}};return function(n){g=h=-(l=f=1/0),x=[],Zo.geo.stream(n,_);var t=x.length;if(t){x.sort(c);for(var e,r=1,u=x[0],i=[u];t>r;++r)e=x[r],s(e[0],u)||s(e[1],u)?(a(u[0],e[1])>a(u[0],u[1])&&(u[1]=e[1]),a(e[0],u[1])>a(u[0],u[1])&&(u[0]=e[0])):i.push(u=e);
+for(var o,e,p=-1/0,t=i.length-1,r=0,u=i[t];t>=r;u=e,++r)e=i[r],(o=a(u[1],e[0]))>p&&(p=o,l=e[0],h=u[1])}return x=M=null,1/0===l||1/0===f?[[0/0,0/0],[0/0,0/0]]:[[l,f],[h,g]]}}(),Zo.geo.centroid=function(n){hc=gc=pc=vc=dc=mc=yc=xc=Mc=_c=bc=0,Zo.geo.stream(n,wc);var t=Mc,e=_c,r=bc,u=t*t+e*e+r*r;return Ea>u&&(t=mc,e=yc,r=xc,ka>gc&&(t=pc,e=vc,r=dc),u=t*t+e*e+r*r,Ea>u)?[0/0,0/0]:[Math.atan2(e,t)*Ca,G(r/Math.sqrt(u))*Ca]};var hc,gc,pc,vc,dc,mc,yc,xc,Mc,_c,bc,wc={sphere:v,point:ye,lineStart:Me,lineEnd:_e,polygonStart:function(){wc.lineStart=be},polygonEnd:function(){wc.lineStart=Me}},Sc=Ae(we,Te,Re,[-ba,-ba/2]),kc=1e9;Zo.geo.clipExtent=function(){var n,t,e,r,u,i,o={stream:function(n){return u&&(u.valid=!1),u=i(n),u.valid=!0,u},extent:function(a){return arguments.length?(i=Ue(n=+a[0][0],t=+a[0][1],e=+a[1][0],r=+a[1][1]),u&&(u.valid=!1,u=null),o):[[n,t],[e,r]]}};return o.extent([[0,0],[960,500]])},(Zo.geo.conicEqualArea=function(){return He(Fe)}).raw=Fe,Zo.geo.albers=function(){return Zo.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},Zo.geo.albersUsa=function(){function n(n){var i=n[0],o=n[1];return t=null,e(i,o),t||(r(i,o),t)||u(i,o),t}var t,e,r,u,i=Zo.geo.albers(),o=Zo.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),a=Zo.geo.conicEqualArea().rotate([157,0]).center([-3,19.9]).parallels([8,18]),c={point:function(n,e){t=[n,e]}};return n.invert=function(n){var t=i.scale(),e=i.translate(),r=(n[0]-e[0])/t,u=(n[1]-e[1])/t;return(u>=.12&&.234>u&&r>=-.425&&-.214>r?o:u>=.166&&.234>u&&r>=-.214&&-.115>r?a:i).invert(n)},n.stream=function(n){var t=i.stream(n),e=o.stream(n),r=a.stream(n);return{point:function(n,u){t.point(n,u),e.point(n,u),r.point(n,u)},sphere:function(){t.sphere(),e.sphere(),r.sphere()},lineStart:function(){t.lineStart(),e.lineStart(),r.lineStart()},lineEnd:function(){t.lineEnd(),e.lineEnd(),r.lineEnd()},polygonStart:function(){t.polygonStart(),e.polygonStart(),r.polygonStart()},polygonEnd:function(){t.polygonEnd(),e.polygonEnd(),r.polygonEnd()}}},n.precision=function(t){return arguments.length?(i.precision(t),o.precision(t),a.precision(t),n):i.precision()},n.scale=function(t){return arguments.length?(i.scale(t),o.scale(.35*t),a.scale(t),n.translate(i.translate())):i.scale()},n.translate=function(t){if(!arguments.length)return i.translate();var s=i.scale(),l=+t[0],f=+t[1];return e=i.translate(t).clipExtent([[l-.455*s,f-.238*s],[l+.455*s,f+.238*s]]).stream(c).point,r=o.translate([l-.307*s,f+.201*s]).clipExtent([[l-.425*s+ka,f+.12*s+ka],[l-.214*s-ka,f+.234*s-ka]]).stream(c).point,u=a.translate([l-.205*s,f+.212*s]).clipExtent([[l-.214*s+ka,f+.166*s+ka],[l-.115*s-ka,f+.234*s-ka]]).stream(c).point,n},n.scale(1070)};var Ec,Ac,Cc,Nc,zc,Lc,Tc={point:v,lineStart:v,lineEnd:v,polygonStart:function(){Ac=0,Tc.lineStart=Oe},polygonEnd:function(){Tc.lineStart=Tc.lineEnd=Tc.point=v,Ec+=ua(Ac/2)}},qc={point:Ye,lineStart:v,lineEnd:v,polygonStart:v,polygonEnd:v},Rc={point:Ve,lineStart:Xe,lineEnd:$e,polygonStart:function(){Rc.lineStart=Be},polygonEnd:function(){Rc.point=Ve,Rc.lineStart=Xe,Rc.lineEnd=$e}};Zo.geo.path=function(){function n(n){return n&&("function"==typeof a&&i.pointRadius(+a.apply(this,arguments)),o&&o.valid||(o=u(i)),Zo.geo.stream(n,o)),i.result()}function t(){return o=null,n}var e,r,u,i,o,a=4.5;return n.area=function(n){return Ec=0,Zo.geo.stream(n,u(Tc)),Ec},n.centroid=function(n){return pc=vc=dc=mc=yc=xc=Mc=_c=bc=0,Zo.geo.stream(n,u(Rc)),bc?[Mc/bc,_c/bc]:xc?[mc/xc,yc/xc]:dc?[pc/dc,vc/dc]:[0/0,0/0]},n.bounds=function(n){return zc=Lc=-(Cc=Nc=1/0),Zo.geo.stream(n,u(qc)),[[Cc,Nc],[zc,Lc]]},n.projection=function(n){return arguments.length?(u=(e=n)?n.stream||Ge(n):wt,t()):e},n.context=function(n){return arguments.length?(i=null==(r=n)?new Ie:new We(n),"function"!=typeof a&&i.pointRadius(a),t()):r},n.pointRadius=function(t){return arguments.length?(a="function"==typeof t?t:(i.pointRadius(+t),+t),n):a},n.projection(Zo.geo.albersUsa()).context(null)},Zo.geo.transform=function(n){return{stream:function(t){var e=new Ke(t);for(var r in n)e[r]=n[r];return e}}},Ke.prototype={point:function(n,t){this.stream.point(n,t)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}},Zo.geo.projection=nr,Zo.geo.projectionMutator=tr,(Zo.geo.equirectangular=function(){return nr(rr)}).raw=rr.invert=rr,Zo.geo.rotation=function(n){function t(t){return t=n(t[0]*Aa,t[1]*Aa),t[0]*=Ca,t[1]*=Ca,t}return n=ir(n[0]%360*Aa,n[1]*Aa,n.length>2?n[2]*Aa:0),t.invert=function(t){return t=n.invert(t[0]*Aa,t[1]*Aa),t[0]*=Ca,t[1]*=Ca,t},t},ur.invert=rr,Zo.geo.circle=function(){function n(){var n="function"==typeof r?r.apply(this,arguments):r,t=ir(-n[0]*Aa,-n[1]*Aa,0).invert,u=[];return e(null,null,1,{point:function(n,e){u.push(n=t(n,e)),n[0]*=Ca,n[1]*=Ca}}),{type:"Polygon",coordinates:[u]}}var t,e,r=[0,0],u=6;return n.origin=function(t){return arguments.length?(r=t,n):r},n.angle=function(r){return arguments.length?(e=sr((t=+r)*Aa,u*Aa),n):t},n.precision=function(r){return arguments.length?(e=sr(t*Aa,(u=+r)*Aa),n):u},n.angle(90)},Zo.geo.distance=function(n,t){var e,r=(t[0]-n[0])*Aa,u=n[1]*Aa,i=t[1]*Aa,o=Math.sin(r),a=Math.cos(r),c=Math.sin(u),s=Math.cos(u),l=Math.sin(i),f=Math.cos(i);return Math.atan2(Math.sqrt((e=f*o)*e+(e=s*l-c*f*a)*e),c*l+s*f*a)},Zo.geo.graticule=function(){function n(){return{type:"MultiLineString",coordinates:t()}}function t(){return Zo.range(Math.ceil(i/d)*d,u,d).map(h).concat(Zo.range(Math.ceil(s/m)*m,c,m).map(g)).concat(Zo.range(Math.ceil(r/p)*p,e,p).filter(function(n){return ua(n%d)>ka}).map(l)).concat(Zo.range(Math.ceil(a/v)*v,o,v).filter(function(n){return ua(n%m)>ka}).map(f))}var e,r,u,i,o,a,c,s,l,f,h,g,p=10,v=p,d=90,m=360,y=2.5;return n.lines=function(){return t().map(function(n){return{type:"LineString",coordinates:n}})},n.outline=function(){return{type:"Polygon",coordinates:[h(i).concat(g(c).slice(1),h(u).reverse().slice(1),g(s).reverse().slice(1))]}},n.extent=function(t){return arguments.length?n.majorExtent(t).minorExtent(t):n.minorExtent()},n.majorExtent=function(t){return arguments.length?(i=+t[0][0],u=+t[1][0],s=+t[0][1],c=+t[1][1],i>u&&(t=i,i=u,u=t),s>c&&(t=s,s=c,c=t),n.precision(y)):[[i,s],[u,c]]},n.minorExtent=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],a=+t[0][1],o=+t[1][1],r>e&&(t=r,r=e,e=t),a>o&&(t=a,a=o,o=t),n.precision(y)):[[r,a],[e,o]]},n.step=function(t){return arguments.length?n.majorStep(t).minorStep(t):n.minorStep()},n.majorStep=function(t){return arguments.length?(d=+t[0],m=+t[1],n):[d,m]},n.minorStep=function(t){return arguments.length?(p=+t[0],v=+t[1],n):[p,v]},n.precision=function(t){return arguments.length?(y=+t,l=fr(a,o,90),f=hr(r,e,y),h=fr(s,c,90),g=hr(i,u,y),n):y},n.majorExtent([[-180,-90+ka],[180,90-ka]]).minorExtent([[-180,-80-ka],[180,80+ka]])},Zo.geo.greatArc=function(){function n(){return{type:"LineString",coordinates:[t||r.apply(this,arguments),e||u.apply(this,arguments)]}}var t,e,r=gr,u=pr;return n.distance=function(){return Zo.geo.distance(t||r.apply(this,arguments),e||u.apply(this,arguments))},n.source=function(e){return arguments.length?(r=e,t="function"==typeof e?null:e,n):r},n.target=function(t){return arguments.length?(u=t,e="function"==typeof t?null:t,n):u},n.precision=function(){return arguments.length?n:0},n},Zo.geo.interpolate=function(n,t){return vr(n[0]*Aa,n[1]*Aa,t[0]*Aa,t[1]*Aa)},Zo.geo.length=function(n){return Dc=0,Zo.geo.stream(n,Pc),Dc};var Dc,Pc={sphere:v,point:v,lineStart:dr,lineEnd:v,polygonStart:v,polygonEnd:v},Uc=mr(function(n){return Math.sqrt(2/(1+n))},function(n){return 2*Math.asin(n/2)});(Zo.geo.azimuthalEqualArea=function(){return nr(Uc)}).raw=Uc;var jc=mr(function(n){var t=Math.acos(n);return t&&t/Math.sin(t)},wt);(Zo.geo.azimuthalEquidistant=function(){return nr(jc)}).raw=jc,(Zo.geo.conicConformal=function(){return He(yr)}).raw=yr,(Zo.geo.conicEquidistant=function(){return He(xr)}).raw=xr;var Hc=mr(function(n){return 1/n},Math.atan);(Zo.geo.gnomonic=function(){return nr(Hc)}).raw=Hc,Mr.invert=function(n,t){return[n,2*Math.atan(Math.exp(t))-Sa]},(Zo.geo.mercator=function(){return _r(Mr)}).raw=Mr;var Fc=mr(function(){return 1},Math.asin);(Zo.geo.orthographic=function(){return nr(Fc)}).raw=Fc;var Oc=mr(function(n){return 1/(1+n)},function(n){return 2*Math.atan(n)});(Zo.geo.stereographic=function(){return nr(Oc)}).raw=Oc,br.invert=function(n,t){return[-t,2*Math.atan(Math.exp(n))-Sa]},(Zo.geo.transverseMercator=function(){var n=_r(br),t=n.center,e=n.rotate;return n.center=function(n){return n?t([-n[1],n[0]]):(n=t(),[n[1],-n[0]])},n.rotate=function(n){return n?e([n[0],n[1],n.length>2?n[2]+90:90]):(n=e(),[n[0],n[1],n[2]-90])},e([0,0,90])}).raw=br,Zo.geom={},Zo.geom.hull=function(n){function t(n){if(n.length<3)return[];var t,u=bt(e),i=bt(r),o=n.length,a=[],c=[];for(t=0;o>t;t++)a.push([+u.call(this,n[t],t),+i.call(this,n[t],t),t]);for(a.sort(Er),t=0;o>t;t++)c.push([a[t][0],-a[t][1]]);var s=kr(a),l=kr(c),f=l[0]===s[0],h=l[l.length-1]===s[s.length-1],g=[];for(t=s.length-1;t>=0;--t)g.push(n[a[s[t]][2]]);for(t=+f;t<l.length-h;++t)g.push(n[a[l[t]][2]]);return g}var e=wr,r=Sr;return arguments.length?t(n):(t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t)},Zo.geom.polygon=function(n){return sa(n,Yc),n};var Yc=Zo.geom.polygon.prototype=[];Yc.area=function(){for(var n,t=-1,e=this.length,r=this[e-1],u=0;++t<e;)n=r,r=this[t],u+=n[1]*r[0]-n[0]*r[1];return.5*u},Yc.centroid=function(n){var t,e,r=-1,u=this.length,i=0,o=0,a=this[u-1];for(arguments.length||(n=-1/(6*this.area()));++r<u;)t=a,a=this[r],e=t[0]*a[1]-a[0]*t[1],i+=(t[0]+a[0])*e,o+=(t[1]+a[1])*e;return[i*n,o*n]},Yc.clip=function(n){for(var t,e,r,u,i,o,a=Nr(n),c=-1,s=this.length-Nr(this),l=this[s-1];++c<s;){for(t=n.slice(),n.length=0,u=this[c],i=t[(r=t.length-a)-1],e=-1;++e<r;)o=t[e],Ar(o,l,u)?(Ar(i,l,u)||n.push(Cr(i,o,l,u)),n.push(o)):Ar(i,l,u)&&n.push(Cr(i,o,l,u)),i=o;a&&n.push(n[0]),l=u}return n};var Ic,Zc,Vc,Xc,$c,Bc=[],Wc=[];Ur.prototype.prepare=function(){for(var n,t=this.edges,e=t.length;e--;)n=t[e].edge,n.b&&n.a||t.splice(e,1);return t.sort(Hr),t.length},Wr.prototype={start:function(){return this.edge.l===this.site?this.edge.a:this.edge.b},end:function(){return this.edge.l===this.site?this.edge.b:this.edge.a}},Jr.prototype={insert:function(n,t){var e,r,u;if(n){if(t.P=n,t.N=n.N,n.N&&(n.N.P=t),n.N=t,n.R){for(n=n.R;n.L;)n=n.L;n.L=t}else n.R=t;e=n}else this._?(n=nu(this._),t.P=null,t.N=n,n.P=n.L=t,e=n):(t.P=t.N=null,this._=t,e=null);for(t.L=t.R=null,t.U=e,t.C=!0,n=t;e&&e.C;)r=e.U,e===r.L?(u=r.R,u&&u.C?(e.C=u.C=!1,r.C=!0,n=r):(n===e.R&&(Kr(this,e),n=e,e=n.U),e.C=!1,r.C=!0,Qr(this,r))):(u=r.L,u&&u.C?(e.C=u.C=!1,r.C=!0,n=r):(n===e.L&&(Qr(this,e),n=e,e=n.U),e.C=!1,r.C=!0,Kr(this,r))),e=n.U;this._.C=!1},remove:function(n){n.N&&(n.N.P=n.P),n.P&&(n.P.N=n.N),n.N=n.P=null;var t,e,r,u=n.U,i=n.L,o=n.R;if(e=i?o?nu(o):i:o,u?u.L===n?u.L=e:u.R=e:this._=e,i&&o?(r=e.C,e.C=n.C,e.L=i,i.U=e,e!==o?(u=e.U,e.U=n.U,n=e.R,u.L=n,e.R=o,o.U=e):(e.U=u,u=e,n=e.R)):(r=n.C,n=e),n&&(n.U=u),!r){if(n&&n.C)return n.C=!1,void 0;do{if(n===this._)break;if(n===u.L){if(t=u.R,t.C&&(t.C=!1,u.C=!0,Kr(this,u),t=u.R),t.L&&t.L.C||t.R&&t.R.C){t.R&&t.R.C||(t.L.C=!1,t.C=!0,Qr(this,t),t=u.R),t.C=u.C,u.C=t.R.C=!1,Kr(this,u),n=this._;break}}else if(t=u.L,t.C&&(t.C=!1,u.C=!0,Qr(this,u),t=u.L),t.L&&t.L.C||t.R&&t.R.C){t.L&&t.L.C||(t.R.C=!1,t.C=!0,Kr(this,t),t=u.L),t.C=u.C,u.C=t.L.C=!1,Qr(this,u),n=this._;break}t.C=!0,n=u,u=u.U}while(!n.C);n&&(n.C=!1)}}},Zo.geom.voronoi=function(n){function t(n){var t=new Array(n.length),r=a[0][0],u=a[0][1],i=a[1][0],o=a[1][1];return tu(e(n),a).cells.forEach(function(e,a){var c=e.edges,s=e.site,l=t[a]=c.length?c.map(function(n){var t=n.start();return[t.x,t.y]}):s.x>=r&&s.x<=i&&s.y>=u&&s.y<=o?[[r,o],[i,o],[i,u],[r,u]]:[];l.point=n[a]}),t}function e(n){return n.map(function(n,t){return{x:Math.round(i(n,t)/ka)*ka,y:Math.round(o(n,t)/ka)*ka,i:t}})}var r=wr,u=Sr,i=r,o=u,a=Jc;return n?t(n):(t.links=function(n){return tu(e(n)).edges.filter(function(n){return n.l&&n.r}).map(function(t){return{source:n[t.l.i],target:n[t.r.i]}})},t.triangles=function(n){var t=[];return tu(e(n)).cells.forEach(function(e,r){for(var u,i,o=e.site,a=e.edges.sort(Hr),c=-1,s=a.length,l=a[s-1].edge,f=l.l===o?l.r:l.l;++c<s;)u=l,i=f,l=a[c].edge,f=l.l===o?l.r:l.l,r<i.i&&r<f.i&&ru(o,i,f)<0&&t.push([n[r],n[i.i],n[f.i]])}),t},t.x=function(n){return arguments.length?(i=bt(r=n),t):r},t.y=function(n){return arguments.length?(o=bt(u=n),t):u},t.clipExtent=function(n){return arguments.length?(a=null==n?Jc:n,t):a===Jc?null:a},t.size=function(n){return arguments.length?t.clipExtent(n&&[[0,0],n]):a===Jc?null:a&&a[1]},t)};var Jc=[[-1e6,-1e6],[1e6,1e6]];Zo.geom.delaunay=function(n){return Zo.geom.voronoi().triangles(n)},Zo.geom.quadtree=function(n,t,e,r,u){function i(n){function i(n,t,e,r,u,i,o,a){if(!isNaN(e)&&!isNaN(r))if(n.leaf){var c=n.x,l=n.y;if(null!=c)if(ua(c-e)+ua(l-r)<.01)s(n,t,e,r,u,i,o,a);else{var f=n.point;n.x=n.y=n.point=null,s(n,f,c,l,u,i,o,a),s(n,t,e,r,u,i,o,a)}else n.x=e,n.y=r,n.point=t}else s(n,t,e,r,u,i,o,a)}function s(n,t,e,r,u,o,a,c){var s=.5*(u+a),l=.5*(o+c),f=e>=s,h=r>=l,g=(h<<1)+f;n.leaf=!1,n=n.nodes[g]||(n.nodes[g]=ou()),f?u=s:a=s,h?o=l:c=l,i(n,t,e,r,u,o,a,c)}var l,f,h,g,p,v,d,m,y,x=bt(a),M=bt(c);if(null!=t)v=t,d=e,m=r,y=u;else if(m=y=-(v=d=1/0),f=[],h=[],p=n.length,o)for(g=0;p>g;++g)l=n[g],l.x<v&&(v=l.x),l.y<d&&(d=l.y),l.x>m&&(m=l.x),l.y>y&&(y=l.y),f.push(l.x),h.push(l.y);else for(g=0;p>g;++g){var _=+x(l=n[g],g),b=+M(l,g);v>_&&(v=_),d>b&&(d=b),_>m&&(m=_),b>y&&(y=b),f.push(_),h.push(b)}var w=m-v,S=y-d;w>S?y=d+w:m=v+S;var k=ou();if(k.add=function(n){i(k,n,+x(n,++g),+M(n,g),v,d,m,y)},k.visit=function(n){au(n,k,v,d,m,y)},g=-1,null==t){for(;++g<p;)i(k,n[g],f[g],h[g],v,d,m,y);--g}else n.forEach(k.add);return f=h=n=l=null,k}var o,a=wr,c=Sr;return(o=arguments.length)?(a=uu,c=iu,3===o&&(u=e,r=t,e=t=0),i(n)):(i.x=function(n){return arguments.length?(a=n,i):a},i.y=function(n){return arguments.length?(c=n,i):c},i.extent=function(n){return arguments.length?(null==n?t=e=r=u=null:(t=+n[0][0],e=+n[0][1],r=+n[1][0],u=+n[1][1]),i):null==t?null:[[t,e],[r,u]]},i.size=function(n){return arguments.length?(null==n?t=e=r=u=null:(t=e=0,r=+n[0],u=+n[1]),i):null==t?null:[r-t,u-e]},i)},Zo.interpolateRgb=cu,Zo.interpolateObject=su,Zo.interpolateNumber=lu,Zo.interpolateString=fu;var Gc=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,Kc=new RegExp(Gc.source,"g");Zo.interpolate=hu,Zo.interpolators=[function(n,t){var e=typeof t;return("string"===e?Ia.has(t)||/^(#|rgb\(|hsl\()/.test(t)?cu:fu:t instanceof et?cu:Array.isArray(t)?gu:"object"===e&&isNaN(t)?su:lu)(n,t)}],Zo.interpolateArray=gu;var Qc=function(){return wt},ns=Zo.map({linear:Qc,poly:Mu,quad:function(){return mu},cubic:function(){return yu},sin:function(){return _u},exp:function(){return bu},circle:function(){return wu},elastic:Su,back:ku,bounce:function(){return Eu}}),ts=Zo.map({"in":wt,out:vu,"in-out":du,"out-in":function(n){return du(vu(n))}});Zo.ease=function(n){var t=n.indexOf("-"),e=t>=0?n.substring(0,t):n,r=t>=0?n.substring(t+1):"in";return e=ns.get(e)||Qc,r=ts.get(r)||wt,pu(r(e.apply(null,Vo.call(arguments,1))))},Zo.interpolateHcl=Au,Zo.interpolateHsl=Cu,Zo.interpolateLab=Nu,Zo.interpolateRound=zu,Zo.transform=function(n){var t=$o.createElementNS(Zo.ns.prefix.svg,"g");return(Zo.transform=function(n){if(null!=n){t.setAttribute("transform",n);var e=t.transform.baseVal.consolidate()}return new Lu(e?e.matrix:es)})(n)},Lu.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var es={a:1,b:0,c:0,d:1,e:0,f:0};Zo.interpolateTransform=Du,Zo.layout={},Zo.layout.bundle=function(){return function(n){for(var t=[],e=-1,r=n.length;++e<r;)t.push(ju(n[e]));return t}},Zo.layout.chord=function(){function n(){var n,s,f,h,g,p={},v=[],d=Zo.range(i),m=[];for(e=[],r=[],n=0,h=-1;++h<i;){for(s=0,g=-1;++g<i;)s+=u[h][g];v.push(s),m.push(Zo.range(i)),n+=s}for(o&&d.sort(function(n,t){return o(v[n],v[t])}),a&&m.forEach(function(n,t){n.sort(function(n,e){return a(u[t][n],u[t][e])})}),n=(wa-l*i)/n,s=0,h=-1;++h<i;){for(f=s,g=-1;++g<i;){var y=d[h],x=m[y][g],M=u[y][x],_=s,b=s+=M*n;p[y+"-"+x]={index:y,subindex:x,startAngle:_,endAngle:b,value:M}}r[y]={index:y,startAngle:f,endAngle:s,value:(s-f)/n},s+=l}for(h=-1;++h<i;)for(g=h-1;++g<i;){var w=p[h+"-"+g],S=p[g+"-"+h];(w.value||S.value)&&e.push(w.value<S.value?{source:S,target:w}:{source:w,target:S})}c&&t()}function t(){e.sort(function(n,t){return c((n.source.value+n.target.value)/2,(t.source.value+t.target.value)/2)})}var e,r,u,i,o,a,c,s={},l=0;return s.matrix=function(n){return arguments.length?(i=(u=n)&&u.length,e=r=null,s):u},s.padding=function(n){return arguments.length?(l=n,e=r=null,s):l},s.sortGroups=function(n){return arguments.length?(o=n,e=r=null,s):o},s.sortSubgroups=function(n){return arguments.length?(a=n,e=null,s):a},s.sortChords=function(n){return arguments.length?(c=n,e&&t(),s):c},s.chords=function(){return e||n(),e},s.groups=function(){return r||n(),r},s},Zo.layout.force=function(){function n(n){return function(t,e,r,u){if(t.point!==n){var i=t.cx-n.x,o=t.cy-n.y,a=u-e,c=i*i+o*o;if(c>a*a/d){if(p>c){var s=t.charge/c;n.px-=i*s,n.py-=o*s}return!0}if(t.point&&c&&p>c){var s=t.pointCharge/c;n.px-=i*s,n.py-=o*s}}return!t.charge}}function t(n){n.px=Zo.event.x,n.py=Zo.event.y,a.resume()}var e,r,u,i,o,a={},c=Zo.dispatch("start","tick","end"),s=[1,1],l=.9,f=rs,h=us,g=-30,p=is,v=.1,d=.64,m=[],y=[];return a.tick=function(){if((r*=.99)<.005)return c.end({type:"end",alpha:r=0}),!0;var t,e,a,f,h,p,d,x,M,_=m.length,b=y.length;for(e=0;b>e;++e)a=y[e],f=a.source,h=a.target,x=h.x-f.x,M=h.y-f.y,(p=x*x+M*M)&&(p=r*i[e]*((p=Math.sqrt(p))-u[e])/p,x*=p,M*=p,h.x-=x*(d=f.weight/(h.weight+f.weight)),h.y-=M*d,f.x+=x*(d=1-d),f.y+=M*d);if((d=r*v)&&(x=s[0]/2,M=s[1]/2,e=-1,d))for(;++e<_;)a=m[e],a.x+=(x-a.x)*d,a.y+=(M-a.y)*d;if(g)for(Vu(t=Zo.geom.quadtree(m),r,o),e=-1;++e<_;)(a=m[e]).fixed||t.visit(n(a));for(e=-1;++e<_;)a=m[e],a.fixed?(a.x=a.px,a.y=a.py):(a.x-=(a.px-(a.px=a.x))*l,a.y-=(a.py-(a.py=a.y))*l);c.tick({type:"tick",alpha:r})},a.nodes=function(n){return arguments.length?(m=n,a):m},a.links=function(n){return arguments.length?(y=n,a):y},a.size=function(n){return arguments.length?(s=n,a):s},a.linkDistance=function(n){return arguments.length?(f="function"==typeof n?n:+n,a):f},a.distance=a.linkDistance,a.linkStrength=function(n){return arguments.length?(h="function"==typeof n?n:+n,a):h},a.friction=function(n){return arguments.length?(l=+n,a):l},a.charge=function(n){return arguments.length?(g="function"==typeof n?n:+n,a):g},a.chargeDistance=function(n){return arguments.length?(p=n*n,a):Math.sqrt(p)},a.gravity=function(n){return arguments.length?(v=+n,a):v},a.theta=function(n){return arguments.length?(d=n*n,a):Math.sqrt(d)},a.alpha=function(n){return arguments.length?(n=+n,r?r=n>0?n:0:n>0&&(c.start({type:"start",alpha:r=n}),Zo.timer(a.tick)),a):r},a.start=function(){function n(n,r){if(!e){for(e=new Array(c),a=0;c>a;++a)e[a]=[];for(a=0;s>a;++a){var u=y[a];e[u.source.index].push(u.target),e[u.target.index].push(u.source)}}for(var i,o=e[t],a=-1,s=o.length;++a<s;)if(!isNaN(i=o[a][n]))return i;return Math.random()*r}var t,e,r,c=m.length,l=y.length,p=s[0],v=s[1];for(t=0;c>t;++t)(r=m[t]).index=t,r.weight=0;for(t=0;l>t;++t)r=y[t],"number"==typeof r.source&&(r.source=m[r.source]),"number"==typeof r.target&&(r.target=m[r.target]),++r.source.weight,++r.target.weight;for(t=0;c>t;++t)r=m[t],isNaN(r.x)&&(r.x=n("x",p)),isNaN(r.y)&&(r.y=n("y",v)),isNaN(r.px)&&(r.px=r.x),isNaN(r.py)&&(r.py=r.y);if(u=[],"function"==typeof f)for(t=0;l>t;++t)u[t]=+f.call(this,y[t],t);else for(t=0;l>t;++t)u[t]=f;if(i=[],"function"==typeof h)for(t=0;l>t;++t)i[t]=+h.call(this,y[t],t);else for(t=0;l>t;++t)i[t]=h;if(o=[],"function"==typeof g)for(t=0;c>t;++t)o[t]=+g.call(this,m[t],t);else for(t=0;c>t;++t)o[t]=g;return a.resume()},a.resume=function(){return a.alpha(.1)},a.stop=function(){return a.alpha(0)},a.drag=function(){return e||(e=Zo.behavior.drag().origin(wt).on("dragstart.force",Ou).on("drag.force",t).on("dragend.force",Yu)),arguments.length?(this.on("mouseover.force",Iu).on("mouseout.force",Zu).call(e),void 0):e},Zo.rebind(a,c,"on")};var rs=20,us=1,is=1/0;Zo.layout.hierarchy=function(){function n(u){var i,o=[u],a=[];for(u.depth=0;null!=(i=o.pop());)if(a.push(i),(s=e.call(n,i,i.depth))&&(c=s.length)){for(var c,s,l;--c>=0;)o.push(l=s[c]),l.parent=i,l.depth=i.depth+1;r&&(i.value=0),i.children=s}else r&&(i.value=+r.call(n,i,i.depth)||0),delete i.children;return Bu(u,function(n){var e,u;t&&(e=n.children)&&e.sort(t),r&&(u=n.parent)&&(u.value+=n.value)}),a}var t=Gu,e=Wu,r=Ju;return n.sort=function(e){return arguments.length?(t=e,n):t},n.children=function(t){return arguments.length?(e=t,n):e},n.value=function(t){return arguments.length?(r=t,n):r},n.revalue=function(t){return r&&($u(t,function(n){n.children&&(n.value=0)}),Bu(t,function(t){var e;t.children||(t.value=+r.call(n,t,t.depth)||0),(e=t.parent)&&(e.value+=t.value)})),t},n},Zo.layout.partition=function(){function n(t,e,r,u){var i=t.children;if(t.x=e,t.y=t.depth*u,t.dx=r,t.dy=u,i&&(o=i.length)){var o,a,c,s=-1;for(r=t.value?r/t.value:0;++s<o;)n(a=i[s],e,c=a.value*r,u),e+=c}}function t(n){var e=n.children,r=0;if(e&&(u=e.length))for(var u,i=-1;++i<u;)r=Math.max(r,t(e[i]));return 1+r}function e(e,i){var o=r.call(this,e,i);return n(o[0],0,u[0],u[1]/t(o[0])),o}var r=Zo.layout.hierarchy(),u=[1,1];return e.size=function(n){return arguments.length?(u=n,e):u},Xu(e,r)},Zo.layout.pie=function(){function n(i){var o=i.map(function(e,r){return+t.call(n,e,r)}),a=+("function"==typeof r?r.apply(this,arguments):r),c=(("function"==typeof u?u.apply(this,arguments):u)-a)/Zo.sum(o),s=Zo.range(i.length);null!=e&&s.sort(e===os?function(n,t){return o[t]-o[n]}:function(n,t){return e(i[n],i[t])});var l=[];return s.forEach(function(n){var t;l[n]={data:i[n],value:t=o[n],startAngle:a,endAngle:a+=t*c}}),l}var t=Number,e=os,r=0,u=wa;return n.value=function(e){return arguments.length?(t=e,n):t},n.sort=function(t){return arguments.length?(e=t,n):e},n.startAngle=function(t){return arguments.length?(r=t,n):r},n.endAngle=function(t){return arguments.length?(u=t,n):u},n};var os={};Zo.layout.stack=function(){function n(a,c){var s=a.map(function(e,r){return t.call(n,e,r)}),l=s.map(function(t){return t.map(function(t,e){return[i.call(n,t,e),o.call(n,t,e)]})}),f=e.call(n,l,c);s=Zo.permute(s,f),l=Zo.permute(l,f);var h,g,p,v=r.call(n,l,c),d=s.length,m=s[0].length;for(g=0;m>g;++g)for(u.call(n,s[0][g],p=v[g],l[0][g][1]),h=1;d>h;++h)u.call(n,s[h][g],p+=l[h-1][g][1],l[h][g][1]);return a}var t=wt,e=ei,r=ri,u=ti,i=Qu,o=ni;return n.values=function(e){return arguments.length?(t=e,n):t},n.order=function(t){return arguments.length?(e="function"==typeof t?t:as.get(t)||ei,n):e},n.offset=function(t){return arguments.length?(r="function"==typeof t?t:cs.get(t)||ri,n):r},n.x=function(t){return arguments.length?(i=t,n):i},n.y=function(t){return arguments.length?(o=t,n):o},n.out=function(t){return arguments.length?(u=t,n):u},n};var as=Zo.map({"inside-out":function(n){var t,e,r=n.length,u=n.map(ui),i=n.map(ii),o=Zo.range(r).sort(function(n,t){return u[n]-u[t]}),a=0,c=0,s=[],l=[];for(t=0;r>t;++t)e=o[t],c>a?(a+=i[e],s.push(e)):(c+=i[e],l.push(e));return l.reverse().concat(s)},reverse:function(n){return Zo.range(n.length).reverse()},"default":ei}),cs=Zo.map({silhouette:function(n){var t,e,r,u=n.length,i=n[0].length,o=[],a=0,c=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];r>a&&(a=r),o.push(r)}for(e=0;i>e;++e)c[e]=(a-o[e])/2;return c},wiggle:function(n){var t,e,r,u,i,o,a,c,s,l=n.length,f=n[0],h=f.length,g=[];for(g[0]=c=s=0,e=1;h>e;++e){for(t=0,u=0;l>t;++t)u+=n[t][e][1];for(t=0,i=0,a=f[e][0]-f[e-1][0];l>t;++t){for(r=0,o=(n[t][e][1]-n[t][e-1][1])/(2*a);t>r;++r)o+=(n[r][e][1]-n[r][e-1][1])/a;i+=o*n[t][e][1]}g[e]=c-=u?i/u*a:0,s>c&&(s=c)}for(e=0;h>e;++e)g[e]-=s;return g},expand:function(n){var t,e,r,u=n.length,i=n[0].length,o=1/u,a=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];if(r)for(t=0;u>t;t++)n[t][e][1]/=r;else for(t=0;u>t;t++)n[t][e][1]=o}for(e=0;i>e;++e)a[e]=0;return a},zero:ri});Zo.layout.histogram=function(){function n(n,i){for(var o,a,c=[],s=n.map(e,this),l=r.call(this,s,i),f=u.call(this,l,s,i),i=-1,h=s.length,g=f.length-1,p=t?1:1/h;++i<g;)o=c[i]=[],o.dx=f[i+1]-(o.x=f[i]),o.y=0;if(g>0)for(i=-1;++i<h;)a=s[i],a>=l[0]&&a<=l[1]&&(o=c[Zo.bisect(f,a,1,g)-1],o.y+=p,o.push(n[i]));return c}var t=!0,e=Number,r=si,u=ai;return n.value=function(t){return arguments.length?(e=t,n):e},n.range=function(t){return arguments.length?(r=bt(t),n):r},n.bins=function(t){return arguments.length?(u="number"==typeof t?function(n){return ci(n,t)}:bt(t),n):u},n.frequency=function(e){return arguments.length?(t=!!e,n):t},n},Zo.layout.pack=function(){function n(n,i){var o=e.call(this,n,i),a=o[0],c=u[0],s=u[1],l=null==t?Math.sqrt:"function"==typeof t?t:function(){return t};if(a.x=a.y=0,Bu(a,function(n){n.r=+l(n.value)}),Bu(a,pi),r){var f=r*(t?1:Math.max(2*a.r/c,2*a.r/s))/2;Bu(a,function(n){n.r+=f}),Bu(a,pi),Bu(a,function(n){n.r-=f})}return mi(a,c/2,s/2,t?1:1/Math.max(2*a.r/c,2*a.r/s)),o}var t,e=Zo.layout.hierarchy().sort(li),r=0,u=[1,1];return n.size=function(t){return arguments.length?(u=t,n):u},n.radius=function(e){return arguments.length?(t=null==e||"function"==typeof e?e:+e,n):t},n.padding=function(t){return arguments.length?(r=+t,n):r},Xu(n,e)},Zo.layout.tree=function(){function n(n,u){var l=o.call(this,n,u),f=l[0],h=t(f);if(Bu(h,e),h.parent.m=-h.z,$u(h,r),s)$u(f,i);else{var g=f,p=f,v=f;$u(f,function(n){n.x<g.x&&(g=n),n.x>p.x&&(p=n),n.depth>v.depth&&(v=n)});var d=a(g,p)/2-g.x,m=c[0]/(p.x+a(p,g)/2+d),y=c[1]/(v.depth||1);$u(f,function(n){n.x=(n.x+d)*m,n.y=n.depth*y})}return l}function t(n){for(var t,e={A:null,children:[n]},r=[e];null!=(t=r.pop());)for(var u,i=t.children,o=0,a=i.length;a>o;++o)r.push((i[o]=u={_:i[o],parent:t,children:(u=i[o].children)&&u.slice()||[],A:null,a:null,z:0,m:0,c:0,s:0,t:null,i:o}).a=u);return e.children[0]}function e(n){var t=n.children,e=n.parent.children,r=n.i?e[n.i-1]:null;if(t.length){wi(n);var i=(t[0].z+t[t.length-1].z)/2;r?(n.z=r.z+a(n._,r._),n.m=n.z-i):n.z=i}else r&&(n.z=r.z+a(n._,r._));n.parent.A=u(n,r,n.parent.A||e[0])}function r(n){n._.x=n.z+n.parent.m,n.m+=n.parent.m}function u(n,t,e){if(t){for(var r,u=n,i=n,o=t,c=u.parent.children[0],s=u.m,l=i.m,f=o.m,h=c.m;o=_i(o),u=Mi(u),o&&u;)c=Mi(c),i=_i(i),i.a=n,r=o.z+f-u.z-s+a(o._,u._),r>0&&(bi(Si(o,n,e),n,r),s+=r,l+=r),f+=o.m,s+=u.m,h+=c.m,l+=i.m;o&&!_i(i)&&(i.t=o,i.m+=f-l),u&&!Mi(c)&&(c.t=u,c.m+=s-h,e=n)}return e}function i(n){n.x*=c[0],n.y=n.depth*c[1]}var o=Zo.layout.hierarchy().sort(null).value(null),a=xi,c=[1,1],s=null;return n.separation=function(t){return arguments.length?(a=t,n):a},n.size=function(t){return arguments.length?(s=null==(c=t)?i:null,n):s?null:c},n.nodeSize=function(t){return arguments.length?(s=null==(c=t)?null:i,n):s?c:null},Xu(n,o)},Zo.layout.cluster=function(){function n(n,i){var o,a=t.call(this,n,i),c=a[0],s=0;Bu(c,function(n){var t=n.children;t&&t.length?(n.x=Ei(t),n.y=ki(t)):(n.x=o?s+=e(n,o):0,n.y=0,o=n)});var l=Ai(c),f=Ci(c),h=l.x-e(l,f)/2,g=f.x+e(f,l)/2;return Bu(c,u?function(n){n.x=(n.x-c.x)*r[0],n.y=(c.y-n.y)*r[1]}:function(n){n.x=(n.x-h)/(g-h)*r[0],n.y=(1-(c.y?n.y/c.y:1))*r[1]}),a}var t=Zo.layout.hierarchy().sort(null).value(null),e=xi,r=[1,1],u=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(u=null==(r=t),n):u?null:r},n.nodeSize=function(t){return arguments.length?(u=null!=(r=t),n):u?r:null},Xu(n,t)},Zo.layout.treemap=function(){function n(n,t){for(var e,r,u=-1,i=n.length;++u<i;)r=(e=n[u]).value*(0>t?0:t),e.area=isNaN(r)||0>=r?0:r}function t(e){var i=e.children;if(i&&i.length){var o,a,c,s=f(e),l=[],h=i.slice(),p=1/0,v="slice"===g?s.dx:"dice"===g?s.dy:"slice-dice"===g?1&e.depth?s.dy:s.dx:Math.min(s.dx,s.dy);for(n(h,s.dx*s.dy/e.value),l.area=0;(c=h.length)>0;)l.push(o=h[c-1]),l.area+=o.area,"squarify"!==g||(a=r(l,v))<=p?(h.pop(),p=a):(l.area-=l.pop().area,u(l,v,s,!1),v=Math.min(s.dx,s.dy),l.length=l.area=0,p=1/0);l.length&&(u(l,v,s,!0),l.length=l.area=0),i.forEach(t)}}function e(t){var r=t.children;if(r&&r.length){var i,o=f(t),a=r.slice(),c=[];for(n(a,o.dx*o.dy/t.value),c.area=0;i=a.pop();)c.push(i),c.area+=i.area,null!=i.z&&(u(c,i.z?o.dx:o.dy,o,!a.length),c.length=c.area=0);r.forEach(e)}}function r(n,t){for(var e,r=n.area,u=0,i=1/0,o=-1,a=n.length;++o<a;)(e=n[o].area)&&(i>e&&(i=e),e>u&&(u=e));return r*=r,t*=t,r?Math.max(t*u*p/r,r/(t*i*p)):1/0}function u(n,t,e,r){var u,i=-1,o=n.length,a=e.x,s=e.y,l=t?c(n.area/t):0;if(t==e.dx){for((r||l>e.dy)&&(l=e.dy);++i<o;)u=n[i],u.x=a,u.y=s,u.dy=l,a+=u.dx=Math.min(e.x+e.dx-a,l?c(u.area/l):0);u.z=!0,u.dx+=e.x+e.dx-a,e.y+=l,e.dy-=l}else{for((r||l>e.dx)&&(l=e.dx);++i<o;)u=n[i],u.x=a,u.y=s,u.dx=l,s+=u.dy=Math.min(e.y+e.dy-s,l?c(u.area/l):0);u.z=!1,u.dy+=e.y+e.dy-s,e.x+=l,e.dx-=l}}function i(r){var u=o||a(r),i=u[0];return i.x=0,i.y=0,i.dx=s[0],i.dy=s[1],o&&a.revalue(i),n([i],i.dx*i.dy/i.value),(o?e:t)(i),h&&(o=u),u}var o,a=Zo.layout.hierarchy(),c=Math.round,s=[1,1],l=null,f=Ni,h=!1,g="squarify",p=.5*(1+Math.sqrt(5));return i.size=function(n){return arguments.length?(s=n,i):s},i.padding=function(n){function t(t){var e=n.call(i,t,t.depth);return null==e?Ni(t):zi(t,"number"==typeof e?[e,e,e,e]:e)}function e(t){return zi(t,n)}if(!arguments.length)return l;var r;return f=null==(l=n)?Ni:"function"==(r=typeof n)?t:"number"===r?(n=[n,n,n,n],e):e,i},i.round=function(n){return arguments.length?(c=n?Math.round:Number,i):c!=Number},i.sticky=function(n){return arguments.length?(h=n,o=null,i):h},i.ratio=function(n){return arguments.length?(p=n,i):p},i.mode=function(n){return arguments.length?(g=n+"",i):g},Xu(i,a)},Zo.random={normal:function(n,t){var e=arguments.length;return 2>e&&(t=1),1>e&&(n=0),function(){var e,r,u;do e=2*Math.random()-1,r=2*Math.random()-1,u=e*e+r*r;while(!u||u>1);return n+t*e*Math.sqrt(-2*Math.log(u)/u)}},logNormal:function(){var n=Zo.random.normal.apply(Zo,arguments);return function(){return Math.exp(n())}},bates:function(n){var t=Zo.random.irwinHall(n);return function(){return t()/n}},irwinHall:function(n){return function(){for(var t=0,e=0;n>e;e++)t+=Math.random();return t}}},Zo.scale={};var ss={floor:wt,ceil:wt};Zo.scale.linear=function(){return Ui([0,1],[0,1],hu,!1)};var ls={s:1,g:1,p:1,r:1,e:1};Zo.scale.log=function(){return Vi(Zo.scale.linear().domain([0,1]),10,!0,[1,10])};var fs=Zo.format(".0e"),hs={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};Zo.scale.pow=function(){return Xi(Zo.scale.linear(),1,[0,1])},Zo.scale.sqrt=function(){return Zo.scale.pow().exponent(.5)},Zo.scale.ordinal=function(){return Bi([],{t:"range",a:[[]]})},Zo.scale.category10=function(){return Zo.scale.ordinal().range(gs)},Zo.scale.category20=function(){return Zo.scale.ordinal().range(ps)},Zo.scale.category20b=function(){return Zo.scale.ordinal().range(vs)},Zo.scale.category20c=function(){return Zo.scale.ordinal().range(ds)};var gs=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(vt),ps=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(vt),vs=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map(vt),ds=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(vt);Zo.scale.quantile=function(){return Wi([],[])},Zo.scale.quantize=function(){return Ji(0,1,[0,1])},Zo.scale.threshold=function(){return Gi([.5],[0,1])},Zo.scale.identity=function(){return Ki([0,1])},Zo.svg={},Zo.svg.arc=function(){function n(){var n=t.apply(this,arguments),i=e.apply(this,arguments),o=r.apply(this,arguments)+ms,a=u.apply(this,arguments)+ms,c=(o>a&&(c=o,o=a,a=c),a-o),s=ba>c?"0":"1",l=Math.cos(o),f=Math.sin(o),h=Math.cos(a),g=Math.sin(a);
+return c>=ys?n?"M0,"+i+"A"+i+","+i+" 0 1,1 0,"+-i+"A"+i+","+i+" 0 1,1 0,"+i+"M0,"+n+"A"+n+","+n+" 0 1,0 0,"+-n+"A"+n+","+n+" 0 1,0 0,"+n+"Z":"M0,"+i+"A"+i+","+i+" 0 1,1 0,"+-i+"A"+i+","+i+" 0 1,1 0,"+i+"Z":n?"M"+i*l+","+i*f+"A"+i+","+i+" 0 "+s+",1 "+i*h+","+i*g+"L"+n*h+","+n*g+"A"+n+","+n+" 0 "+s+",0 "+n*l+","+n*f+"Z":"M"+i*l+","+i*f+"A"+i+","+i+" 0 "+s+",1 "+i*h+","+i*g+"L0,0"+"Z"}var t=Qi,e=no,r=to,u=eo;return n.innerRadius=function(e){return arguments.length?(t=bt(e),n):t},n.outerRadius=function(t){return arguments.length?(e=bt(t),n):e},n.startAngle=function(t){return arguments.length?(r=bt(t),n):r},n.endAngle=function(t){return arguments.length?(u=bt(t),n):u},n.centroid=function(){var n=(t.apply(this,arguments)+e.apply(this,arguments))/2,i=(r.apply(this,arguments)+u.apply(this,arguments))/2+ms;return[Math.cos(i)*n,Math.sin(i)*n]},n};var ms=-Sa,ys=wa-ka;Zo.svg.line=function(){return ro(wt)};var xs=Zo.map({linear:uo,"linear-closed":io,step:oo,"step-before":ao,"step-after":co,basis:po,"basis-open":vo,"basis-closed":mo,bundle:yo,cardinal:fo,"cardinal-open":so,"cardinal-closed":lo,monotone:So});xs.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var Ms=[0,2/3,1/3,0],_s=[0,1/3,2/3,0],bs=[0,1/6,2/3,1/6];Zo.svg.line.radial=function(){var n=ro(ko);return n.radius=n.x,delete n.x,n.angle=n.y,delete n.y,n},ao.reverse=co,co.reverse=ao,Zo.svg.area=function(){return Eo(wt)},Zo.svg.area.radial=function(){var n=Eo(ko);return n.radius=n.x,delete n.x,n.innerRadius=n.x0,delete n.x0,n.outerRadius=n.x1,delete n.x1,n.angle=n.y,delete n.y,n.startAngle=n.y0,delete n.y0,n.endAngle=n.y1,delete n.y1,n},Zo.svg.chord=function(){function n(n,a){var c=t(this,i,n,a),s=t(this,o,n,a);return"M"+c.p0+r(c.r,c.p1,c.a1-c.a0)+(e(c,s)?u(c.r,c.p1,c.r,c.p0):u(c.r,c.p1,s.r,s.p0)+r(s.r,s.p1,s.a1-s.a0)+u(s.r,s.p1,c.r,c.p0))+"Z"}function t(n,t,e,r){var u=t.call(n,e,r),i=a.call(n,u,r),o=c.call(n,u,r)+ms,l=s.call(n,u,r)+ms;return{r:i,a0:o,a1:l,p0:[i*Math.cos(o),i*Math.sin(o)],p1:[i*Math.cos(l),i*Math.sin(l)]}}function e(n,t){return n.a0==t.a0&&n.a1==t.a1}function r(n,t,e){return"A"+n+","+n+" 0 "+ +(e>ba)+",1 "+t}function u(n,t,e,r){return"Q 0,0 "+r}var i=gr,o=pr,a=Ao,c=to,s=eo;return n.radius=function(t){return arguments.length?(a=bt(t),n):a},n.source=function(t){return arguments.length?(i=bt(t),n):i},n.target=function(t){return arguments.length?(o=bt(t),n):o},n.startAngle=function(t){return arguments.length?(c=bt(t),n):c},n.endAngle=function(t){return arguments.length?(s=bt(t),n):s},n},Zo.svg.diagonal=function(){function n(n,u){var i=t.call(this,n,u),o=e.call(this,n,u),a=(i.y+o.y)/2,c=[i,{x:i.x,y:a},{x:o.x,y:a},o];return c=c.map(r),"M"+c[0]+"C"+c[1]+" "+c[2]+" "+c[3]}var t=gr,e=pr,r=Co;return n.source=function(e){return arguments.length?(t=bt(e),n):t},n.target=function(t){return arguments.length?(e=bt(t),n):e},n.projection=function(t){return arguments.length?(r=t,n):r},n},Zo.svg.diagonal.radial=function(){var n=Zo.svg.diagonal(),t=Co,e=n.projection;return n.projection=function(n){return arguments.length?e(No(t=n)):t},n},Zo.svg.symbol=function(){function n(n,r){return(ws.get(t.call(this,n,r))||To)(e.call(this,n,r))}var t=Lo,e=zo;return n.type=function(e){return arguments.length?(t=bt(e),n):t},n.size=function(t){return arguments.length?(e=bt(t),n):e},n};var ws=Zo.map({circle:To,cross:function(n){var t=Math.sqrt(n/5)/2;return"M"+-3*t+","+-t+"H"+-t+"V"+-3*t+"H"+t+"V"+-t+"H"+3*t+"V"+t+"H"+t+"V"+3*t+"H"+-t+"V"+t+"H"+-3*t+"Z"},diamond:function(n){var t=Math.sqrt(n/(2*As)),e=t*As;return"M0,"+-t+"L"+e+",0"+" 0,"+t+" "+-e+",0"+"Z"},square:function(n){var t=Math.sqrt(n)/2;return"M"+-t+","+-t+"L"+t+","+-t+" "+t+","+t+" "+-t+","+t+"Z"},"triangle-down":function(n){var t=Math.sqrt(n/Es),e=t*Es/2;return"M0,"+e+"L"+t+","+-e+" "+-t+","+-e+"Z"},"triangle-up":function(n){var t=Math.sqrt(n/Es),e=t*Es/2;return"M0,"+-e+"L"+t+","+e+" "+-t+","+e+"Z"}});Zo.svg.symbolTypes=ws.keys();var Ss,ks,Es=Math.sqrt(3),As=Math.tan(30*Aa),Cs=[],Ns=0;Cs.call=pa.call,Cs.empty=pa.empty,Cs.node=pa.node,Cs.size=pa.size,Zo.transition=function(n){return arguments.length?Ss?n.transition():n:ma.transition()},Zo.transition.prototype=Cs,Cs.select=function(n){var t,e,r,u=this.id,i=[];n=b(n);for(var o=-1,a=this.length;++o<a;){i.push(t=[]);for(var c=this[o],s=-1,l=c.length;++s<l;)(r=c[s])&&(e=n.call(r,r.__data__,s,o))?("__data__"in r&&(e.__data__=r.__data__),Po(e,s,u,r.__transition__[u]),t.push(e)):t.push(null)}return qo(i,u)},Cs.selectAll=function(n){var t,e,r,u,i,o=this.id,a=[];n=w(n);for(var c=-1,s=this.length;++c<s;)for(var l=this[c],f=-1,h=l.length;++f<h;)if(r=l[f]){i=r.__transition__[o],e=n.call(r,r.__data__,f,c),a.push(t=[]);for(var g=-1,p=e.length;++g<p;)(u=e[g])&&Po(u,g,o,i),t.push(u)}return qo(a,o)},Cs.filter=function(n){var t,e,r,u=[];"function"!=typeof n&&(n=R(n));for(var i=0,o=this.length;o>i;i++){u.push(t=[]);for(var e=this[i],a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return qo(u,this.id)},Cs.tween=function(n,t){var e=this.id;return arguments.length<2?this.node().__transition__[e].tween.get(n):P(this,null==t?function(t){t.__transition__[e].tween.remove(n)}:function(r){r.__transition__[e].tween.set(n,t)})},Cs.attr=function(n,t){function e(){this.removeAttribute(a)}function r(){this.removeAttributeNS(a.space,a.local)}function u(n){return null==n?e:(n+="",function(){var t,e=this.getAttribute(a);return e!==n&&(t=o(e,n),function(n){this.setAttribute(a,t(n))})})}function i(n){return null==n?r:(n+="",function(){var t,e=this.getAttributeNS(a.space,a.local);return e!==n&&(t=o(e,n),function(n){this.setAttributeNS(a.space,a.local,t(n))})})}if(arguments.length<2){for(t in n)this.attr(t,n[t]);return this}var o="transform"==n?Du:hu,a=Zo.ns.qualify(n);return Ro(this,"attr."+n,t,a.local?i:u)},Cs.attrTween=function(n,t){function e(n,e){var r=t.call(this,n,e,this.getAttribute(u));return r&&function(n){this.setAttribute(u,r(n))}}function r(n,e){var r=t.call(this,n,e,this.getAttributeNS(u.space,u.local));return r&&function(n){this.setAttributeNS(u.space,u.local,r(n))}}var u=Zo.ns.qualify(n);return this.tween("attr."+n,u.local?r:e)},Cs.style=function(n,t,e){function r(){this.style.removeProperty(n)}function u(t){return null==t?r:(t+="",function(){var r,u=Wo.getComputedStyle(this,null).getPropertyValue(n);return u!==t&&(r=hu(u,t),function(t){this.style.setProperty(n,r(t),e)})})}var i=arguments.length;if(3>i){if("string"!=typeof n){2>i&&(t="");for(e in n)this.style(e,n[e],t);return this}e=""}return Ro(this,"style."+n,t,u)},Cs.styleTween=function(n,t,e){function r(r,u){var i=t.call(this,r,u,Wo.getComputedStyle(this,null).getPropertyValue(n));return i&&function(t){this.style.setProperty(n,i(t),e)}}return arguments.length<3&&(e=""),this.tween("style."+n,r)},Cs.text=function(n){return Ro(this,"text",n,Do)},Cs.remove=function(){return this.each("end.transition",function(){var n;this.__transition__.count<2&&(n=this.parentNode)&&n.removeChild(this)})},Cs.ease=function(n){var t=this.id;return arguments.length<1?this.node().__transition__[t].ease:("function"!=typeof n&&(n=Zo.ease.apply(Zo,arguments)),P(this,function(e){e.__transition__[t].ease=n}))},Cs.delay=function(n){var t=this.id;return arguments.length<1?this.node().__transition__[t].delay:P(this,"function"==typeof n?function(e,r,u){e.__transition__[t].delay=+n.call(e,e.__data__,r,u)}:(n=+n,function(e){e.__transition__[t].delay=n}))},Cs.duration=function(n){var t=this.id;return arguments.length<1?this.node().__transition__[t].duration:P(this,"function"==typeof n?function(e,r,u){e.__transition__[t].duration=Math.max(1,n.call(e,e.__data__,r,u))}:(n=Math.max(1,n),function(e){e.__transition__[t].duration=n}))},Cs.each=function(n,t){var e=this.id;if(arguments.length<2){var r=ks,u=Ss;Ss=e,P(this,function(t,r,u){ks=t.__transition__[e],n.call(t,t.__data__,r,u)}),ks=r,Ss=u}else P(this,function(r){var u=r.__transition__[e];(u.event||(u.event=Zo.dispatch("start","end"))).on(n,t)});return this},Cs.transition=function(){for(var n,t,e,r,u=this.id,i=++Ns,o=[],a=0,c=this.length;c>a;a++){o.push(n=[]);for(var t=this[a],s=0,l=t.length;l>s;s++)(e=t[s])&&(r=Object.create(e.__transition__[u]),r.delay+=r.duration,Po(e,s,i,r)),n.push(e)}return qo(o,i)},Zo.svg.axis=function(){function n(n){n.each(function(){var n,s=Zo.select(this),l=this.__chart__||e,f=this.__chart__=e.copy(),h=null==c?f.ticks?f.ticks.apply(f,a):f.domain():c,g=null==t?f.tickFormat?f.tickFormat.apply(f,a):wt:t,p=s.selectAll(".tick").data(h,f),v=p.enter().insert("g",".domain").attr("class","tick").style("opacity",ka),d=Zo.transition(p.exit()).style("opacity",ka).remove(),m=Zo.transition(p.order()).style("opacity",1),y=Ti(f),x=s.selectAll(".domain").data([0]),M=(x.enter().append("path").attr("class","domain"),Zo.transition(x));v.append("line"),v.append("text");var _=v.select("line"),b=m.select("line"),w=p.select("text").text(g),S=v.select("text"),k=m.select("text");switch(r){case"bottom":n=Uo,_.attr("y2",u),S.attr("y",Math.max(u,0)+o),b.attr("x2",0).attr("y2",u),k.attr("x",0).attr("y",Math.max(u,0)+o),w.attr("dy",".71em").style("text-anchor","middle"),M.attr("d","M"+y[0]+","+i+"V0H"+y[1]+"V"+i);break;case"top":n=Uo,_.attr("y2",-u),S.attr("y",-(Math.max(u,0)+o)),b.attr("x2",0).attr("y2",-u),k.attr("x",0).attr("y",-(Math.max(u,0)+o)),w.attr("dy","0em").style("text-anchor","middle"),M.attr("d","M"+y[0]+","+-i+"V0H"+y[1]+"V"+-i);break;case"left":n=jo,_.attr("x2",-u),S.attr("x",-(Math.max(u,0)+o)),b.attr("x2",-u).attr("y2",0),k.attr("x",-(Math.max(u,0)+o)).attr("y",0),w.attr("dy",".32em").style("text-anchor","end"),M.attr("d","M"+-i+","+y[0]+"H0V"+y[1]+"H"+-i);break;case"right":n=jo,_.attr("x2",u),S.attr("x",Math.max(u,0)+o),b.attr("x2",u).attr("y2",0),k.attr("x",Math.max(u,0)+o).attr("y",0),w.attr("dy",".32em").style("text-anchor","start"),M.attr("d","M"+i+","+y[0]+"H0V"+y[1]+"H"+i)}if(f.rangeBand){var E=f,A=E.rangeBand()/2;l=f=function(n){return E(n)+A}}else l.rangeBand?l=f:d.call(n,f);v.call(n,l),m.call(n,f)})}var t,e=Zo.scale.linear(),r=zs,u=6,i=6,o=3,a=[10],c=null;return n.scale=function(t){return arguments.length?(e=t,n):e},n.orient=function(t){return arguments.length?(r=t in Ls?t+"":zs,n):r},n.ticks=function(){return arguments.length?(a=arguments,n):a},n.tickValues=function(t){return arguments.length?(c=t,n):c},n.tickFormat=function(e){return arguments.length?(t=e,n):t},n.tickSize=function(t){var e=arguments.length;return e?(u=+t,i=+arguments[e-1],n):u},n.innerTickSize=function(t){return arguments.length?(u=+t,n):u},n.outerTickSize=function(t){return arguments.length?(i=+t,n):i},n.tickPadding=function(t){return arguments.length?(o=+t,n):o},n.tickSubdivide=function(){return arguments.length&&n},n};var zs="bottom",Ls={top:1,right:1,bottom:1,left:1};Zo.svg.brush=function(){function n(i){i.each(function(){var i=Zo.select(this).style("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",u).on("touchstart.brush",u),o=i.selectAll(".background").data([0]);o.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),i.selectAll(".extent").data([0]).enter().append("rect").attr("class","extent").style("cursor","move");var a=i.selectAll(".resize").data(p,wt);a.exit().remove(),a.enter().append("g").attr("class",function(n){return"resize "+n}).style("cursor",function(n){return Ts[n]}).append("rect").attr("x",function(n){return/[ew]$/.test(n)?-3:null}).attr("y",function(n){return/^[ns]/.test(n)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),a.style("display",n.empty()?"none":null);var l,f=Zo.transition(i),h=Zo.transition(o);c&&(l=Ti(c),h.attr("x",l[0]).attr("width",l[1]-l[0]),e(f)),s&&(l=Ti(s),h.attr("y",l[0]).attr("height",l[1]-l[0]),r(f)),t(f)})}function t(n){n.selectAll(".resize").attr("transform",function(n){return"translate("+l[+/e$/.test(n)]+","+f[+/^s/.test(n)]+")"})}function e(n){n.select(".extent").attr("x",l[0]),n.selectAll(".extent,.n>rect,.s>rect").attr("width",l[1]-l[0])}function r(n){n.select(".extent").attr("y",f[0]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",f[1]-f[0])}function u(){function u(){32==Zo.event.keyCode&&(C||(x=null,z[0]-=l[1],z[1]-=f[1],C=2),y())}function p(){32==Zo.event.keyCode&&2==C&&(z[0]+=l[1],z[1]+=f[1],C=0,y())}function v(){var n=Zo.mouse(_),u=!1;M&&(n[0]+=M[0],n[1]+=M[1]),C||(Zo.event.altKey?(x||(x=[(l[0]+l[1])/2,(f[0]+f[1])/2]),z[0]=l[+(n[0]<x[0])],z[1]=f[+(n[1]<x[1])]):x=null),E&&d(n,c,0)&&(e(S),u=!0),A&&d(n,s,1)&&(r(S),u=!0),u&&(t(S),w({type:"brush",mode:C?"move":"resize"}))}function d(n,t,e){var r,u,a=Ti(t),c=a[0],s=a[1],p=z[e],v=e?f:l,d=v[1]-v[0];return C&&(c-=p,s-=d+p),r=(e?g:h)?Math.max(c,Math.min(s,n[e])):n[e],C?u=(r+=p)+d:(x&&(p=Math.max(c,Math.min(s,2*x[e]-r))),r>p?(u=r,r=p):u=p),v[0]!=r||v[1]!=u?(e?o=null:i=null,v[0]=r,v[1]=u,!0):void 0}function m(){v(),S.style("pointer-events","all").selectAll(".resize").style("display",n.empty()?"none":null),Zo.select("body").style("cursor",null),L.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),N(),w({type:"brushend"})}var x,M,_=this,b=Zo.select(Zo.event.target),w=a.of(_,arguments),S=Zo.select(_),k=b.datum(),E=!/^(n|s)$/.test(k)&&c,A=!/^(e|w)$/.test(k)&&s,C=b.classed("extent"),N=I(),z=Zo.mouse(_),L=Zo.select(Wo).on("keydown.brush",u).on("keyup.brush",p);if(Zo.event.changedTouches?L.on("touchmove.brush",v).on("touchend.brush",m):L.on("mousemove.brush",v).on("mouseup.brush",m),S.interrupt().selectAll("*").interrupt(),C)z[0]=l[0]-z[0],z[1]=f[0]-z[1];else if(k){var T=+/w$/.test(k),q=+/^n/.test(k);M=[l[1-T]-z[0],f[1-q]-z[1]],z[0]=l[T],z[1]=f[q]}else Zo.event.altKey&&(x=z.slice());S.style("pointer-events","none").selectAll(".resize").style("display",null),Zo.select("body").style("cursor",b.style("cursor")),w({type:"brushstart"}),v()}var i,o,a=M(n,"brushstart","brush","brushend"),c=null,s=null,l=[0,0],f=[0,0],h=!0,g=!0,p=qs[0];return n.event=function(n){n.each(function(){var n=a.of(this,arguments),t={x:l,y:f,i:i,j:o},e=this.__chart__||t;this.__chart__=t,Ss?Zo.select(this).transition().each("start.brush",function(){i=e.i,o=e.j,l=e.x,f=e.y,n({type:"brushstart"})}).tween("brush:brush",function(){var e=gu(l,t.x),r=gu(f,t.y);return i=o=null,function(u){l=t.x=e(u),f=t.y=r(u),n({type:"brush",mode:"resize"})}}).each("end.brush",function(){i=t.i,o=t.j,n({type:"brush",mode:"resize"}),n({type:"brushend"})}):(n({type:"brushstart"}),n({type:"brush",mode:"resize"}),n({type:"brushend"}))})},n.x=function(t){return arguments.length?(c=t,p=qs[!c<<1|!s],n):c},n.y=function(t){return arguments.length?(s=t,p=qs[!c<<1|!s],n):s},n.clamp=function(t){return arguments.length?(c&&s?(h=!!t[0],g=!!t[1]):c?h=!!t:s&&(g=!!t),n):c&&s?[h,g]:c?h:s?g:null},n.extent=function(t){var e,r,u,a,h;return arguments.length?(c&&(e=t[0],r=t[1],s&&(e=e[0],r=r[0]),i=[e,r],c.invert&&(e=c(e),r=c(r)),e>r&&(h=e,e=r,r=h),(e!=l[0]||r!=l[1])&&(l=[e,r])),s&&(u=t[0],a=t[1],c&&(u=u[1],a=a[1]),o=[u,a],s.invert&&(u=s(u),a=s(a)),u>a&&(h=u,u=a,a=h),(u!=f[0]||a!=f[1])&&(f=[u,a])),n):(c&&(i?(e=i[0],r=i[1]):(e=l[0],r=l[1],c.invert&&(e=c.invert(e),r=c.invert(r)),e>r&&(h=e,e=r,r=h))),s&&(o?(u=o[0],a=o[1]):(u=f[0],a=f[1],s.invert&&(u=s.invert(u),a=s.invert(a)),u>a&&(h=u,u=a,a=h))),c&&s?[[e,u],[r,a]]:c?[e,r]:s&&[u,a])},n.clear=function(){return n.empty()||(l=[0,0],f=[0,0],i=o=null),n},n.empty=function(){return!!c&&l[0]==l[1]||!!s&&f[0]==f[1]},Zo.rebind(n,a,"on")};var Ts={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},qs=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Rs=Qa.format=ic.timeFormat,Ds=Rs.utc,Ps=Ds("%Y-%m-%dT%H:%M:%S.%LZ");Rs.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?Ho:Ps,Ho.parse=function(n){var t=new Date(n);return isNaN(t)?null:t},Ho.toString=Ps.toString,Qa.second=Dt(function(n){return new nc(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return n.getSeconds()}),Qa.seconds=Qa.second.range,Qa.seconds.utc=Qa.second.utc.range,Qa.minute=Dt(function(n){return new nc(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return n.getMinutes()}),Qa.minutes=Qa.minute.range,Qa.minutes.utc=Qa.minute.utc.range,Qa.hour=Dt(function(n){var t=n.getTimezoneOffset()/60;return new nc(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return n.getHours()}),Qa.hours=Qa.hour.range,Qa.hours.utc=Qa.hour.utc.range,Qa.month=Dt(function(n){return n=Qa.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return n.getMonth()}),Qa.months=Qa.month.range,Qa.months.utc=Qa.month.utc.range;var Us=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],js=[[Qa.second,1],[Qa.second,5],[Qa.second,15],[Qa.second,30],[Qa.minute,1],[Qa.minute,5],[Qa.minute,15],[Qa.minute,30],[Qa.hour,1],[Qa.hour,3],[Qa.hour,6],[Qa.hour,12],[Qa.day,1],[Qa.day,2],[Qa.week,1],[Qa.month,1],[Qa.month,3],[Qa.year,1]],Hs=Rs.multi([[".%L",function(n){return n.getMilliseconds()}],[":%S",function(n){return n.getSeconds()}],["%I:%M",function(n){return n.getMinutes()}],["%I %p",function(n){return n.getHours()}],["%a %d",function(n){return n.getDay()&&1!=n.getDate()}],["%b %d",function(n){return 1!=n.getDate()}],["%B",function(n){return n.getMonth()}],["%Y",we]]),Fs={range:function(n,t,e){return Zo.range(Math.ceil(n/e)*e,+t,e).map(Oo)},floor:wt,ceil:wt};js.year=Qa.year,Qa.scale=function(){return Fo(Zo.scale.linear(),js,Hs)};var Os=js.map(function(n){return[n[0].utc,n[1]]}),Ys=Ds.multi([[".%L",function(n){return n.getUTCMilliseconds()}],[":%S",function(n){return n.getUTCSeconds()}],["%I:%M",function(n){return n.getUTCMinutes()}],["%I %p",function(n){return n.getUTCHours()}],["%a %d",function(n){return n.getUTCDay()&&1!=n.getUTCDate()}],["%b %d",function(n){return 1!=n.getUTCDate()}],["%B",function(n){return n.getUTCMonth()}],["%Y",we]]);Os.year=Qa.year.utc,Qa.scale.utc=function(){return Fo(Zo.scale.linear(),Os,Ys)},Zo.text=St(function(n){return n.responseText}),Zo.json=function(n,t){return kt(n,"application/json",Yo,t)},Zo.html=function(n,t){return kt(n,"text/html",Io,t)},Zo.xml=St(function(n){return n.responseXML}),"function"==typeof define&&define.amd?define(Zo):"object"==typeof module&&module.exports&&(module.exports=Zo),this.d3=Zo}(); \ No newline at end of file
diff --git a/third_party/webkit/PerformanceTests/MotionMark/resources/debug-runner/graph.js b/third_party/webkit/PerformanceTests/MotionMark/resources/debug-runner/graph.js
new file mode 100644
index 0000000000..4803936219
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/resources/debug-runner/graph.js
@@ -0,0 +1,615 @@
+Utilities.extendObject(window.benchmarkController, {
+ updateGraphData: function(testResult, testData, options)
+ {
+ var element = document.getElementById("test-graph-data");
+ element.innerHTML = "";
+ element._testResult = testResult;
+ element._options = options;
+
+ var margins = new Insets(30, 30, 30, 40);
+ var size = Point.elementClientSize(element);
+ size.y = window.innerHeight - element.offsetTop;
+ size = size.subtract(margins.size);
+
+ // Convert from compact JSON output to propertied data
+ var samplesWithProperties = {};
+ [Strings.json.controller, Strings.json.complexity, Strings.json.complexityAverage].forEach(function(seriesName) {
+ var series = testData[Strings.json.samples][seriesName];
+ samplesWithProperties[seriesName] = series.toArray();
+ })
+
+ this.createTimeGraph(testResult, samplesWithProperties[Strings.json.controller], testData[Strings.json.marks], testData[Strings.json.controller], options, margins, size);
+ this.onTimeGraphOptionsChanged();
+
+ this._showOrHideNodes(true, "form[name=graph-type]");
+ document.forms["graph-type"].elements["type"] = "complexity";
+ this.createComplexityGraph(testResult, testData[Strings.json.controller], samplesWithProperties, options, margins, size);
+ this.onComplexityGraphOptionsChanged();
+
+ this.onGraphTypeChanged();
+ },
+
+ _addRegressionLine: function(parent, xScale, yScale, points, range, isAlongYAxis)
+ {
+ var polygon = [];
+ var line = []
+ var xRange = isAlongYAxis ? range : 0;
+ var yRange = isAlongYAxis ? 0 : range;
+ for (var i = 0; i < points.length; ++i) {
+ var point = points[i];
+ var x;
+ if (xRange instanceof Array)
+ x = xRange[0];
+ else
+ x = point[0] + xRange;
+ polygon.push(xScale(x), yScale(point[1] + yRange));
+ line.push(xScale(point[0]), yScale(point[1]));
+ }
+ for (var i = points.length - 1; i >= 0; --i) {
+ var point = points[i];
+ var x;
+ if (xRange instanceof Array)
+ x = xRange[1];
+ else
+ x = point[0] - xRange;
+ polygon.push(xScale(x), yScale(point[1] - yRange));
+ }
+ parent.append("polygon")
+ .attr("points", polygon.join(","));
+ parent.append("line")
+ .attr("x1", line[0])
+ .attr("y1", line[1])
+ .attr("x2", line[2])
+ .attr("y2", line[3]);
+ },
+
+ _addRegression: function(data, svg, xScale, yScale)
+ {
+ svg.append("circle")
+ .attr("cx", xScale(data.segment1[1][0]))
+ .attr("cy", yScale(data.segment1[1][1]))
+ .attr("r", 5);
+ this._addRegressionLine(svg, xScale, yScale, data.segment1, data.stdev);
+ this._addRegressionLine(svg, xScale, yScale, data.segment2, data.stdev);
+ },
+
+ createComplexityGraph: function(result, timeRegressions, data, options, margins, size)
+ {
+ var svg = d3.select("#test-graph-data").append("svg")
+ .attr("id", "complexity-graph")
+ .attr("class", "hidden")
+ .attr("width", size.width + margins.left + margins.right)
+ .attr("height", size.height + margins.top + margins.bottom)
+ .append("g")
+ .attr("transform", "translate(" + margins.left + "," + margins.top + ")");
+
+ var timeSamples = data[Strings.json.controller];
+
+ var xMin = 100000, xMax = 0;
+ if (timeRegressions) {
+ timeRegressions.forEach(function(regression) {
+ for (var i = regression.startIndex; i <= regression.endIndex; ++i) {
+ xMin = Math.min(xMin, timeSamples[i].complexity);
+ xMax = Math.max(xMax, timeSamples[i].complexity);
+ }
+ });
+ } else {
+ xMin = d3.min(timeSamples, function(s) { return s.complexity; });
+ xMax = d3.max(timeSamples, function(s) { return s.complexity; });
+ }
+
+ var xScale = d3.scale.linear()
+ .range([0, size.width])
+ .domain([xMin, xMax]);
+ var yScale = d3.scale.linear()
+ .range([size.height, 0])
+ .domain([1000/20, 1000/60]);
+
+ var xAxis = d3.svg.axis()
+ .scale(xScale)
+ .orient("bottom");
+ var yAxis = d3.svg.axis()
+ .scale(yScale)
+ .tickValues([1000/20, 1000/25, 1000/30, 1000/35, 1000/40, 1000/45, 1000/50, 1000/55, 1000/60])
+ .tickFormat(function(d) { return (1000 / d).toFixed(0); })
+ .orient("left");
+
+ // x-axis
+ svg.append("g")
+ .attr("class", "x axis")
+ .attr("transform", "translate(0," + size.height + ")")
+ .call(xAxis);
+
+ // y-axis
+ svg.append("g")
+ .attr("class", "y axis")
+ .call(yAxis);
+
+ // time result
+ var mean = svg.append("g")
+ .attr("class", "mean complexity");
+ var timeResult = result[Strings.json.controller];
+ var yMin = yScale.domain()[0], yMax = yScale.domain()[1];
+ this._addRegressionLine(mean, xScale, yScale, [[timeResult.average, yMin], [timeResult.average, yMax]], timeResult.stdev, true);
+
+ // regression
+ this._addRegression(result[Strings.json.complexity], svg.append("g").attr("class", "regression raw"), xScale, yScale);
+ this._addRegression(result[Strings.json.complexityAverage], svg.append("g").attr("class", "regression average"), xScale, yScale);
+
+ var bootstrapResult = result[Strings.json.complexity][Strings.json.bootstrap];
+ if (bootstrapResult) {
+ var histogram = d3.layout.histogram()
+ .bins(xScale.ticks(100))(bootstrapResult.data);
+ var yBootstrapScale = d3.scale.linear()
+ .range([size.height/2, 0])
+ .domain([0, d3.max(histogram, function(d) { return d.y; })]);
+ group = svg.append("g").attr("class", "bootstrap");
+ var bar = group.selectAll(".bar")
+ .data(histogram)
+ .enter().append("g")
+ .attr("class", "bar")
+ .attr("transform", function(d) { return "translate(" + xScale(d.x) + "," + yBootstrapScale(d.y) + ")"; });
+ bar.append("rect")
+ .attr("x", 1)
+ .attr("y", size.height/2)
+ .attr("width", xScale(histogram[1].x) - xScale(histogram[0].x) - 1)
+ .attr("height", function(d) { return size.height/2 - yBootstrapScale(d.y); });
+ group = group.append("g").attr("class", "median");
+ this._addRegressionLine(group, xScale, yScale, [[bootstrapResult.median, yMin], [bootstrapResult.median, yMax]], [bootstrapResult.confidenceLow, bootstrapResult.confidenceHigh], true);
+ group.append("circle")
+ .attr("cx", xScale(bootstrapResult.median))
+ .attr("cy", yScale(1000/60))
+ .attr("r", 5);
+ }
+
+ // series
+ group = svg.append("g")
+ .attr("class", "series raw")
+ .selectAll("line")
+ .data(data[Strings.json.complexity])
+ .enter();
+ group.append("line")
+ .attr("x1", function(d) { return xScale(d.complexity) - 3; })
+ .attr("x2", function(d) { return xScale(d.complexity) + 3; })
+ .attr("y1", function(d) { return yScale(d.frameLength) - 3; })
+ .attr("y2", function(d) { return yScale(d.frameLength) + 3; });
+ group.append("line")
+ .attr("x1", function(d) { return xScale(d.complexity) - 3; })
+ .attr("x2", function(d) { return xScale(d.complexity) + 3; })
+ .attr("y1", function(d) { return yScale(d.frameLength) + 3; })
+ .attr("y2", function(d) { return yScale(d.frameLength) - 3; });
+
+ group = svg.append("g")
+ .attr("class", "series average")
+ .selectAll("circle")
+ .data(data[Strings.json.complexityAverage])
+ .enter();
+ group.append("circle")
+ .attr("cx", function(d) { return xScale(d.complexity); })
+ .attr("cy", function(d) { return yScale(d.frameLength); })
+ .attr("r", 3)
+ group.append("line")
+ .attr("x1", function(d) { return xScale(d.complexity); })
+ .attr("x2", function(d) { return xScale(d.complexity); })
+ .attr("y1", function(d) { return yScale(d.frameLength - d.stdev); })
+ .attr("y2", function(d) { return yScale(d.frameLength + d.stdev); });
+
+ // Cursor
+ var cursorGroup = svg.append("g").attr("class", "cursor hidden");
+ cursorGroup.append("line")
+ .attr("class", "x")
+ .attr("x1", 0)
+ .attr("x2", 0)
+ .attr("y1", yScale(yAxis.scale().domain()[0]) + 10)
+ .attr("y2", yScale(yAxis.scale().domain()[1]));
+ cursorGroup.append("line")
+ .attr("class", "y")
+ .attr("x1", xScale(xAxis.scale().domain()[0]) - 10)
+ .attr("x2", xScale(xAxis.scale().domain()[1]))
+ .attr("y1", 0)
+ .attr("y2", 0)
+ cursorGroup.append("text")
+ .attr("class", "label x")
+ .attr("x", 0)
+ .attr("y", yScale(yAxis.scale().domain()[0]) + 15)
+ .attr("baseline-shift", "-100%")
+ .attr("text-anchor", "middle");
+ cursorGroup.append("text")
+ .attr("class", "label y")
+ .attr("x", xScale(xAxis.scale().domain()[0]) - 15)
+ .attr("y", 0)
+ .attr("baseline-shift", "-30%")
+ .attr("text-anchor", "end");
+ // Area to handle mouse events
+ var area = svg.append("rect")
+ .attr("fill", "transparent")
+ .attr("x", 0)
+ .attr("y", 0)
+ .attr("width", size.width)
+ .attr("height", size.height);
+
+ area.on("mouseover", function() {
+ document.querySelector("#complexity-graph .cursor").classList.remove("hidden");
+ }).on("mouseout", function() {
+ document.querySelector("#complexity-graph .cursor").classList.add("hidden");
+ }).on("mousemove", function() {
+ var location = d3.mouse(this);
+ var location_domain = [xScale.invert(location[0]), yScale.invert(location[1])];
+ cursorGroup.select("line.x")
+ .attr("x1", location[0])
+ .attr("x2", location[0]);
+ cursorGroup.select("text.x")
+ .attr("x", location[0])
+ .text(location_domain[0].toFixed(1));
+ cursorGroup.select("line.y")
+ .attr("y1", location[1])
+ .attr("y2", location[1]);
+ cursorGroup.select("text.y")
+ .attr("y", location[1])
+ .text((1000 / location_domain[1]).toFixed(1));
+ });
+ },
+
+ createTimeGraph: function(result, samples, marks, regressions, options, margins, size)
+ {
+ var svg = d3.select("#test-graph-data").append("svg")
+ .attr("id", "time-graph")
+ .attr("width", size.width + margins.left + margins.right)
+ .attr("height", size.height + margins.top + margins.bottom)
+ .append("g")
+ .attr("transform", "translate(" + margins.left + "," + margins.top + ")");
+
+ // Axis scales
+ var x = d3.scale.linear()
+ .range([0, size.width])
+ .domain([
+ Math.min(d3.min(samples, function(s) { return s.time; }), 0),
+ d3.max(samples, function(s) { return s.time; })]);
+ var complexityMax = d3.max(samples, function(s) {
+ if (s.time > 0)
+ return s.complexity;
+ return 0;
+ });
+
+ var yLeft = d3.scale.linear()
+ .range([size.height, 0])
+ .domain([0, complexityMax]);
+ var yRight = d3.scale.linear()
+ .range([size.height, 0])
+ .domain([1000/20, 1000/60]);
+
+ // Axes
+ var xAxis = d3.svg.axis()
+ .scale(x)
+ .orient("bottom")
+ .tickFormat(function(d) { return (d/1000).toFixed(0); });
+ var yAxisLeft = d3.svg.axis()
+ .scale(yLeft)
+ .orient("left");
+ var yAxisRight = d3.svg.axis()
+ .scale(yRight)
+ .tickValues([1000/20, 1000/25, 1000/30, 1000/35, 1000/40, 1000/45, 1000/50, 1000/55, 1000/60])
+ .tickFormat(function(d) { return (1000/d).toFixed(0); })
+ .orient("right");
+
+ // x-axis
+ svg.append("g")
+ .attr("class", "x axis")
+ .attr("fill", "rgb(235, 235, 235)")
+ .attr("transform", "translate(0," + size.height + ")")
+ .call(xAxis)
+ .append("text")
+ .attr("class", "label")
+ .attr("x", size.width)
+ .attr("y", -6)
+ .attr("fill", "rgb(235, 235, 235)")
+ .style("text-anchor", "end")
+ .text("time");
+
+ // yLeft-axis
+ svg.append("g")
+ .attr("class", "yLeft axis")
+ .attr("fill", "#7ADD49")
+ .call(yAxisLeft)
+ .append("text")
+ .attr("class", "label")
+ .attr("transform", "rotate(-90)")
+ .attr("y", 6)
+ .attr("fill", "#7ADD49")
+ .attr("dy", ".71em")
+ .style("text-anchor", "end")
+ .text(Strings.text.complexity);
+
+ // yRight-axis
+ svg.append("g")
+ .attr("class", "yRight axis")
+ .attr("fill", "#FA4925")
+ .attr("transform", "translate(" + size.width + ", 0)")
+ .call(yAxisRight)
+ .append("text")
+ .attr("class", "label")
+ .attr("x", 9)
+ .attr("y", -20)
+ .attr("fill", "#FA4925")
+ .attr("dy", ".71em")
+ .style("text-anchor", "start")
+ .text(Strings.text.frameRate);
+
+ // marks
+ var yMin = yRight(yAxisRight.scale().domain()[0]);
+ var yMax = yRight(yAxisRight.scale().domain()[1]);
+ for (var markName in marks) {
+ var mark = marks[markName];
+ var xLocation = x(mark.time);
+
+ var markerGroup = svg.append("g")
+ .attr("class", "marker")
+ .attr("transform", "translate(" + xLocation + ", 0)");
+ markerGroup.append("text")
+ .attr("transform", "translate(10, " + (yMin - 10) + ") rotate(-90)")
+ .style("text-anchor", "start")
+ .text(markName)
+ markerGroup.append("line")
+ .attr("x1", 0)
+ .attr("x2", 0)
+ .attr("y1", yMin)
+ .attr("y2", yMax);
+ }
+
+ if (Strings.json.controller in result) {
+ var complexity = result[Strings.json.controller];
+ var regression = svg.append("g")
+ .attr("class", "complexity mean");
+ this._addRegressionLine(regression, x, yLeft, [[samples[0].time, complexity.average], [samples[samples.length - 1].time, complexity.average]], complexity.stdev);
+ }
+ if (Strings.json.frameLength in result) {
+ var frameLength = result[Strings.json.frameLength];
+ var regression = svg.append("g")
+ .attr("class", "fps mean");
+ this._addRegressionLine(regression, x, yRight, [[samples[0].time, 1000/frameLength.average], [samples[samples.length - 1].time, 1000/frameLength.average]], frameLength.stdev);
+ }
+
+ // right-target
+ if (options["controller"] == "adaptive") {
+ var targetFrameLength = 1000 / options["frame-rate"];
+ svg.append("line")
+ .attr("x1", x(0))
+ .attr("x2", size.width)
+ .attr("y1", yRight(targetFrameLength))
+ .attr("y2", yRight(targetFrameLength))
+ .attr("class", "target-fps marker");
+ }
+
+ // Cursor
+ var cursorGroup = svg.append("g").attr("class", "cursor");
+ cursorGroup.append("line")
+ .attr("x1", 0)
+ .attr("x2", 0)
+ .attr("y1", yMin)
+ .attr("y2", yMin);
+
+ // Data
+ var allData = samples;
+ var filteredData = samples.filter(function (sample) {
+ return "smoothedFrameLength" in sample;
+ });
+
+ function addData(name, data, yCoordinateCallback, pointRadius, omitLine) {
+ var svgGroup = svg.append("g").attr("id", name);
+ if (!omitLine) {
+ svgGroup.append("path")
+ .datum(data)
+ .attr("d", d3.svg.line()
+ .x(function(d) { return x(d.time); })
+ .y(yCoordinateCallback));
+ }
+ svgGroup.selectAll("circle")
+ .data(data)
+ .enter()
+ .append("circle")
+ .attr("cx", function(d) { return x(d.time); })
+ .attr("cy", yCoordinateCallback)
+ .attr("r", pointRadius);
+
+ cursorGroup.append("circle")
+ .attr("class", name)
+ .attr("r", pointRadius + 2);
+ }
+
+ addData("complexity", allData, function(d) { return yLeft(d.complexity); }, 2);
+ addData("rawFPS", allData, function(d) { return yRight(d.frameLength); }, 1);
+ addData("filteredFPS", filteredData, function(d) { return yRight(d.smoothedFrameLength); }, 2);
+
+ // regressions
+ var regressionGroup = svg.append("g")
+ .attr("id", "regressions");
+ if (regressions) {
+ var complexities = [];
+ regressions.forEach(function (regression) {
+ if (!isNaN(regression.segment1[0][1]) && !isNaN(regression.segment1[1][1])) {
+ regressionGroup.append("line")
+ .attr("x1", x(regression.segment1[0][0]))
+ .attr("x2", x(regression.segment1[1][0]))
+ .attr("y1", yRight(regression.segment1[0][1]))
+ .attr("y2", yRight(regression.segment1[1][1]));
+ }
+ if (!isNaN(regression.segment2[0][1]) && !isNaN(regression.segment2[1][1])) {
+ regressionGroup.append("line")
+ .attr("x1", x(regression.segment2[0][0]))
+ .attr("x2", x(regression.segment2[1][0]))
+ .attr("y1", yRight(regression.segment2[0][1]))
+ .attr("y2", yRight(regression.segment2[1][1]));
+ }
+ // inflection point
+ regressionGroup.append("circle")
+ .attr("cx", x(regression.segment1[1][0]))
+ .attr("cy", yLeft(regression.complexity))
+ .attr("r", 5);
+ complexities.push(regression.complexity);
+ });
+ if (complexities.length) {
+ var yLeftComplexities = d3.svg.axis()
+ .scale(yLeft)
+ .tickValues(complexities)
+ .tickSize(10)
+ .orient("left");
+ svg.append("g")
+ .attr("class", "complexity yLeft axis")
+ .call(yLeftComplexities);
+ }
+ }
+
+ // Area to handle mouse events
+ var area = svg.append("rect")
+ .attr("fill", "transparent")
+ .attr("x", 0)
+ .attr("y", 0)
+ .attr("width", size.width)
+ .attr("height", size.height);
+
+ var timeBisect = d3.bisector(function(d) { return d.time; }).right;
+ var statsToHighlight = ["complexity", "rawFPS", "filteredFPS"];
+ area.on("mouseover", function() {
+ document.querySelector("#time-graph .cursor").classList.remove("hidden");
+ document.querySelector("#test-graph nav").classList.remove("hide-data");
+ }).on("mouseout", function() {
+ document.querySelector("#time-graph .cursor").classList.add("hidden");
+ document.querySelector("#test-graph nav").classList.add("hide-data");
+ }).on("mousemove", function() {
+ var form = document.forms["time-graph-options"].elements;
+
+ var mx_domain = x.invert(d3.mouse(this)[0]);
+ var index = Math.min(timeBisect(allData, mx_domain), allData.length - 1);
+ var data = allData[index];
+ var cursor_x = x(data.time);
+ var cursor_y = yAxisRight.scale().domain()[1];
+ var ys = [yRight(yAxisRight.scale().domain()[0]), yRight(yAxisRight.scale().domain()[1])];
+
+ document.querySelector("#test-graph nav .time").textContent = (data.time / 1000).toFixed(4) + "s (" + index + ")";
+ statsToHighlight.forEach(function(name) {
+ var element = document.querySelector("#test-graph nav ." + name);
+ var content = "";
+ var data_y = null;
+ switch (name) {
+ case "complexity":
+ content = data.complexity;
+ data_y = yLeft(data.complexity);
+ break;
+ case "rawFPS":
+ content = (1000/data.frameLength).toFixed(2);
+ data_y = yRight(data.frameLength);
+ break;
+ case "filteredFPS":
+ if ("smoothedFrameLength" in data) {
+ content = (1000/data.smoothedFrameLength).toFixed(2);
+ data_y = yRight(data.smoothedFrameLength);
+ }
+ break;
+ }
+
+ element.textContent = content;
+
+ if (form[name].checked && data_y !== null) {
+ ys.push(data_y);
+ cursorGroup.select("." + name)
+ .attr("cx", cursor_x)
+ .attr("cy", data_y);
+ document.querySelector("#time-graph .cursor ." + name).classList.remove("hidden");
+ } else
+ document.querySelector("#time-graph .cursor ." + name).classList.add("hidden");
+ });
+
+ if (form["rawFPS"].checked)
+ cursor_y = Math.max(cursor_y, data.frameLength);
+ cursorGroup.select("line")
+ .attr("x1", cursor_x)
+ .attr("x2", cursor_x)
+ .attr("y1", Math.min.apply(null, ys))
+ .attr("y2", Math.max.apply(null, ys));
+
+ });
+ },
+
+ _showOrHideNodes: function(isShown, selector) {
+ var nodeList = document.querySelectorAll(selector);
+ if (isShown) {
+ for (var i = 0; i < nodeList.length; ++i)
+ nodeList[i].classList.remove("hidden");
+ } else {
+ for (var i = 0; i < nodeList.length; ++i)
+ nodeList[i].classList.add("hidden");
+ }
+ },
+
+ onComplexityGraphOptionsChanged: function() {
+ var form = document.forms["complexity-graph-options"].elements;
+ benchmarkController._showOrHideNodes(form["series-raw"].checked, "#complexity-graph .series.raw");
+ benchmarkController._showOrHideNodes(form["series-average"].checked, "#complexity-graph .series.average");
+ benchmarkController._showOrHideNodes(form["regression-time-score"].checked, "#complexity-graph .mean.complexity");
+ benchmarkController._showOrHideNodes(form["bootstrap-score"].checked, "#complexity-graph .bootstrap");
+ benchmarkController._showOrHideNodes(form["complexity-regression-aggregate-raw"].checked, "#complexity-graph .regression.raw");
+ benchmarkController._showOrHideNodes(form["complexity-regression-aggregate-average"].checked, "#complexity-graph .regression.average");
+ },
+
+ onTimeGraphOptionsChanged: function() {
+ var form = document.forms["time-graph-options"].elements;
+ benchmarkController._showOrHideNodes(form["markers"].checked, ".marker");
+ benchmarkController._showOrHideNodes(form["averages"].checked, "#test-graph-data .mean");
+ benchmarkController._showOrHideNodes(form["complexity"].checked, "#complexity");
+ benchmarkController._showOrHideNodes(form["rawFPS"].checked, "#rawFPS");
+ benchmarkController._showOrHideNodes(form["filteredFPS"].checked, "#filteredFPS");
+ benchmarkController._showOrHideNodes(form["regressions"].checked, "#regressions");
+ },
+
+ onGraphTypeChanged: function() {
+ var form = document.forms["graph-type"].elements;
+ var testResult = document.getElementById("test-graph-data")._testResult;
+ var isTimeSelected = form["graph-type"].value == "time";
+
+ benchmarkController._showOrHideNodes(isTimeSelected, "#time-graph");
+ benchmarkController._showOrHideNodes(isTimeSelected, "form[name=time-graph-options]");
+ benchmarkController._showOrHideNodes(!isTimeSelected, "#complexity-graph");
+ benchmarkController._showOrHideNodes(!isTimeSelected, "form[name=complexity-graph-options]");
+
+ var score = "", mean = "";
+ if (isTimeSelected) {
+ score = testResult[Strings.json.score].toFixed(2);
+
+ var regression = testResult[Strings.json.controller];
+ mean = [
+ "mean: ",
+ regression.average.toFixed(2),
+ " ± ",
+ regression.stdev.toFixed(2),
+ " (",
+ regression.percent.toFixed(2),
+ "%)"];
+ if (regression.concern) {
+ mean = mean.concat([
+ ", worst 5%: ",
+ regression.concern.toFixed(2)]);
+ }
+ mean = mean.join("");
+ } else {
+ var complexityRegression = testResult[Strings.json.complexity];
+ var complexityAverageRegression = testResult[Strings.json.complexityAverage];
+
+ document.getElementById("complexity-regression-aggregate-raw").textContent = complexityRegression.complexity.toFixed(2) + ", ±" + complexityRegression.stdev.toFixed(2) + "ms";
+ document.getElementById("complexity-regression-aggregate-average").textContent = complexityAverageRegression.complexity.toFixed(2) + ", ±" + complexityAverageRegression.stdev.toFixed(2) + "ms";
+
+ var bootstrap = complexityRegression[Strings.json.bootstrap];
+ if (bootstrap) {
+ score = bootstrap.median.toFixed(2);
+ mean = [
+ (bootstrap.confidencePercentage * 100).toFixed(0),
+ "% CI: ",
+ bootstrap.confidenceLow.toFixed(2),
+ "–",
+ bootstrap.confidenceHigh.toFixed(2)
+ ].join("");
+ }
+ }
+
+ sectionsManager.setSectionScore("test-graph", score, mean);
+ }
+});
diff --git a/third_party/webkit/PerformanceTests/MotionMark/resources/debug-runner/tests.js b/third_party/webkit/PerformanceTests/MotionMark/resources/debug-runner/tests.js
new file mode 100644
index 0000000000..accaa3c3df
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/resources/debug-runner/tests.js
@@ -0,0 +1,345 @@
+Utilities.extendObject(Strings.text, {
+ samples: "Samples",
+ complexity: "Time Complexity",
+ frameRate: "FPS",
+ confidenceInterval: "80% Confidence Interval",
+ mergedRawComplexity: "Raw Complexity",
+ graph: "Graph"
+});
+
+
+Utilities.extendObject(Headers, {
+ details: [
+ {
+ title: Strings.text.graph
+ },
+ {
+ title: Strings.text.confidenceInterval,
+ children:
+ [
+ {
+ text: function(data) {
+ return data[Strings.json.complexity][Strings.json.bootstrap].confidenceLow.toFixed(2);
+ },
+ className: "right pad-left pad-right"
+ },
+ {
+ text: function(data) {
+ return " - " + data[Strings.json.complexity][Strings.json.bootstrap].confidenceHigh.toFixed(2);
+ },
+ className: "left"
+ },
+ {
+ text: function(data) {
+ var bootstrap = data[Strings.json.complexity][Strings.json.bootstrap];
+ return (100 * (bootstrap.confidenceLow / bootstrap.median - 1)).toFixed(2) + "%";
+ },
+ className: "left pad-left small"
+ },
+ {
+ text: function(data) {
+ var bootstrap = data[Strings.json.complexity][Strings.json.bootstrap];
+ return "+" + (100 * (bootstrap.confidenceHigh / bootstrap.median - 1)).toFixed(2) + "%";
+ },
+ className: "left pad-left small"
+ }
+ ]
+ },
+ {
+ title: Strings.text.complexity,
+ children:
+ [
+ {
+ text: function(data) {
+ return data[Strings.json.controller][Strings.json.measurements.average].toFixed(2);
+ },
+ className: "average"
+ },
+ {
+ text: function(data) {
+ return [
+ "± ",
+ data[Strings.json.controller][Strings.json.measurements.percent].toFixed(2),
+ "%"
+ ].join("");
+ },
+ className: function(data) {
+ var className = "stdev";
+
+ if (data[Strings.json.controller][Strings.json.measurements.percent] >= 10)
+ className += " noisy-results";
+ return className;
+ }
+ }
+ ]
+ },
+ {
+ title: Strings.text.frameRate,
+ children:
+ [
+ {
+ text: function(data) {
+ return data[Strings.json.frameLength][Strings.json.measurements.average].toFixed(2);
+ },
+ className: function(data, options) {
+ var className = "average";
+ if (Math.abs(data[Strings.json.frameLength][Strings.json.measurements.average] - options["frame-rate"]) >= 2)
+ className += " noisy-results";
+ return className;
+ }
+ },
+ {
+ text: function(data) {
+ var frameRateData = data[Strings.json.frameLength];
+ return [
+ "± ",
+ frameRateData[Strings.json.measurements.percent].toFixed(2),
+ "%"
+ ].join("");
+ },
+ className: function(data) {
+ var className = "stdev";
+
+ if (data[Strings.json.frameLength][Strings.json.measurements.percent] >= 10)
+ className += " noisy-results";
+ return className;
+ }
+ }
+ ]
+ },
+ {
+ title: Strings.text.mergedRawComplexity,
+ children:
+ [
+ {
+ text: function(data) {
+ return data[Strings.json.complexity][Strings.json.complexity].toFixed(2);
+ },
+ className: "average"
+ },
+ {
+ text: function(data) {
+ return [
+ "± ",
+ data[Strings.json.complexity][Strings.json.measurements.stdev].toFixed(2),
+ "ms"
+ ].join("");
+ },
+ className: "stdev"
+ }
+ ]
+ }
+ ]
+})
+
+///////////
+// Suites
+
+Suites.push(new Suite("HTML suite",
+ [
+ {
+ url: "bouncing-particles/bouncing-css-shapes.html?particleWidth=12&particleHeight=12&shape=circle",
+ name: "CSS bouncing circles"
+ },
+ {
+ url: "bouncing-particles/bouncing-css-shapes.html?particleWidth=40&particleHeight=40&shape=rect&clip=star",
+ name: "CSS bouncing clipped rects"
+ },
+ {
+ url: "bouncing-particles/bouncing-css-shapes.html?particleWidth=50&particleHeight=50&shape=circle&fill=gradient",
+ name: "CSS bouncing gradient circles"
+ },
+ {
+ url: "bouncing-particles/bouncing-css-shapes.html?particleWidth=80&particleHeight=80&shape=circle&blend",
+ name: "CSS bouncing blend circles"
+ },
+ {
+ url: "bouncing-particles/bouncing-css-shapes.html?particleWidth=80&particleHeight=80&shape=circle&filter",
+ name: "CSS bouncing filter circles"
+ },
+ {
+ url: "bouncing-particles/bouncing-css-images.html?particleWidth=80&particleHeight=80&imageSrc=../resources/yin-yang.svg",
+ name: "CSS bouncing SVG images"
+ },
+ {
+ url: "bouncing-particles/bouncing-tagged-images.html?particleWidth=100&particleHeight=100",
+ name: "CSS bouncing tagged images"
+ },
+ {
+ url: "dom/leaves.html",
+ name: "Leaves 2.0"
+ },
+ {
+ url: "dom/focus.html",
+ name: "Focus 2.0"
+ },
+ {
+ url: "dom/particles.html",
+ name: "DOM particles, SVG masks"
+ },
+ {
+ url: "dom/compositing-transforms.html?particleWidth=50&particleHeight=50&filters=yes&imageSrc=../resources/yin-yang.svg",
+ name: "Composited Transforms"
+ }
+ ]
+));
+
+Suites.push(new Suite("Canvas suite",
+ [
+ {
+ url: "bouncing-particles/bouncing-canvas-shapes.html?particleWidth=40&particleHeight=40&shape=rect&clip=star",
+ name: "canvas bouncing clipped rects"
+ },
+ {
+ url: "bouncing-particles/bouncing-canvas-shapes.html?particleWidth=50&particleHeight=50&shape=circle&fill=gradient",
+ name: "canvas bouncing gradient circles"
+ },
+ {
+ url: "bouncing-particles/bouncing-canvas-images.html?particleWidth=80&particleHeight=80&imageSrc=../resources/yin-yang.svg",
+ name: "canvas bouncing SVG images"
+ },
+ {
+ url: "bouncing-particles/bouncing-canvas-images.html?particleWidth=80&particleHeight=80&imageSrc=../resources/yin-yang.png",
+ name: "canvas bouncing PNG images"
+ },
+ {
+ url: "simple/simple-canvas-paths.html?pathType=strokes",
+ name: "Stroke shapes"
+ },
+ {
+ url: "simple/simple-canvas-paths.html?pathType=fills",
+ name: "Fill shapes"
+ },
+ {
+ url: "simple/tiled-canvas-image.html",
+ name: "Canvas put/get image data"
+ },
+ ]
+));
+
+Suites.push(new Suite("SVG suite",
+ [
+ {
+ url: "bouncing-particles/bouncing-svg-shapes.html?particleWidth=12&particleHeight=12&shape=circle",
+ name: "SVG bouncing circles",
+ },
+ {
+ url: "bouncing-particles/bouncing-svg-shapes.html?particleWidth=40&particleHeight=40&shape=rect&clip=star",
+ name: "SVG bouncing clipped rects",
+ },
+ {
+ url: "bouncing-particles/bouncing-svg-shapes.html?particleWidth=50&particleHeight=50&shape=circle&fill=gradient",
+ name: "SVG bouncing gradient circles"
+ },
+ {
+ url: "bouncing-particles/bouncing-svg-images.html?particleWidth=80&particleHeight=80&imageSrc=../resources/yin-yang.svg",
+ name: "SVG bouncing SVG images"
+ },
+ {
+ url: "bouncing-particles/bouncing-svg-images.html?particleWidth=80&particleHeight=80&imageSrc=../resources/yin-yang.png",
+ name: "SVG bouncing PNG images"
+ },
+ ]
+));
+
+Suites.push(new Suite("3D Graphics",
+ [
+ {
+ url: "3d/webgl.html",
+ name: "WebGL"
+ },
+ ]
+));
+
+Suites.push(new Suite("Basic canvas path suite",
+ [
+ {
+ url: "simple/simple-canvas-paths.html?pathType=line&lineCap=butt",
+ name: "Canvas line segments, butt caps"
+ },
+ {
+ url: "simple/simple-canvas-paths.html?pathType=line&lineCap=round",
+ name: "Canvas line segments, round caps"
+ },
+ {
+ url: "simple/simple-canvas-paths.html?pathType=line&lineCap=square",
+ name: "Canvas line segments, square caps"
+ },
+ {
+ url: "simple/simple-canvas-paths.html?pathType=linePath&lineJoin=bevel",
+ name: "Canvas line path, bevel join"
+ },
+ {
+ url: "simple/simple-canvas-paths.html?pathType=linePath&lineJoin=round",
+ name: "Canvas line path, round join"
+ },
+ {
+ url: "simple/simple-canvas-paths.html?pathType=linePath&lineJoin=miter",
+ name: "Canvas line path, miter join"
+ },
+ {
+ url: "simple/simple-canvas-paths.html?pathType=linePath&lineDash=1",
+ name: "Canvas line path with dash pattern"
+ },
+ {
+ url: "simple/simple-canvas-paths.html?pathType=quadratic",
+ name: "Canvas quadratic segments"
+ },
+ {
+ url: "simple/simple-canvas-paths.html?pathType=quadraticPath",
+ name: "Canvas quadratic path"
+ },
+ {
+ url: "simple/simple-canvas-paths.html?pathType=bezier",
+ name: "Canvas bezier segments"
+ },
+ {
+ url: "simple/simple-canvas-paths.html?pathType=bezierPath",
+ name: "Canvas bezier path"
+ },
+ {
+ url: "simple/simple-canvas-paths.html?&pathType=arcTo",
+ name: "Canvas arcTo segments"
+ },
+ {
+ url: "simple/simple-canvas-paths.html?pathType=arc",
+ name: "Canvas arc segments"
+ },
+ {
+ url: "simple/simple-canvas-paths.html?pathType=rect",
+ name: "Canvas rects"
+ },
+ {
+ url: "simple/simple-canvas-paths.html?pathType=ellipse",
+ name: "Canvas ellipses"
+ },
+ {
+ url: "simple/simple-canvas-paths.html?pathType=lineFill",
+ name: "Canvas line path, fill"
+ },
+ {
+ url: "simple/simple-canvas-paths.html?pathType=quadraticFill",
+ name: "Canvas quadratic path, fill"
+ },
+ {
+ url: "simple/simple-canvas-paths.html?pathType=bezierFill",
+ name: "Canvas bezier path, fill"
+ },
+ {
+ url: "simple/simple-canvas-paths.html?&pathType=arcToFill",
+ name: "Canvas arcTo segments, fill"
+ },
+ {
+ url: "simple/simple-canvas-paths.html?pathType=arcFill",
+ name: "Canvas arc segments, fill"
+ },
+ {
+ url: "simple/simple-canvas-paths.html?pathType=rectFill",
+ name: "Canvas rects, fill"
+ },
+ {
+ url: "simple/simple-canvas-paths.html?pathType=ellipseFill",
+ name: "Canvas ellipses, fill"
+ }
+ ]
+));
diff --git a/third_party/webkit/PerformanceTests/MotionMark/resources/extensions.js b/third_party/webkit/PerformanceTests/MotionMark/resources/extensions.js
new file mode 100644
index 0000000000..fb9d500877
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/resources/extensions.js
@@ -0,0 +1,670 @@
+Utilities =
+{
+ _parse: function(str, sep)
+ {
+ var output = {};
+ str.split(sep).forEach(function(part) {
+ var item = part.split("=");
+ var value = decodeURIComponent(item[1]);
+ if (value[0] == "'" )
+ 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), "&");
+ },
+
+ parseArguments: function(str)
+ {
+ return this._parse(str, " ");
+ },
+
+ 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;
+ },
+
+ createElement: function(name, attrs, parentElement)
+ {
+ var element = document.createElement(name);
+
+ for (var key in attrs)
+ element.setAttribute(key, attrs[key]);
+
+ parentElement.appendChild(element);
+ return element;
+ },
+
+ createSVGElement: function(name, attrs, xlinkAttrs, parentElement)
+ {
+ const svgNamespace = "http://www.w3.org/2000/svg";
+ const xlinkNamespace = "http://www.w3.org/1999/xlink";
+
+ var element = document.createElementNS(svgNamespace, name);
+
+ for (var key in attrs)
+ element.setAttribute(key, attrs[key]);
+
+ for (var key in xlinkAttrs)
+ element.setAttributeNS(xlinkNamespace, key, xlinkAttrs[key]);
+
+ parentElement.appendChild(element);
+ return element;
+ },
+
+ browserPrefix: function()
+ {
+ // Get the HTML element's CSSStyleDeclaration
+ var styles = window.getComputedStyle(document.documentElement, '');
+
+ // Convert the styles list to an array
+ var stylesArray = Array.prototype.slice.call(styles);
+
+ // Concatenate all the styles in one big string
+ var stylesString = stylesArray.join('');
+
+ // Search the styles string for a known prefix type, settle on Opera if none is found.
+ var prefixes = stylesString.match(/-(moz|webkit|ms)-/) || (styles.OLink === '' && ['', 'o']);
+
+ // prefixes has two elements; e.g. for webkit it has ['-webkit-', 'webkit'];
+ var prefix = prefixes[1];
+
+ // Have 'O' before 'Moz' in the string so it is matched first.
+ var dom = ('WebKit|O|Moz|MS').match(new RegExp(prefix, 'i'))[0];
+
+ // Return all the required prefixes.
+ return {
+ dom: dom,
+ lowercase: prefix,
+ css: '-' + prefix + '-',
+ js: prefix[0].toUpperCase() + prefix.substr(1)
+ };
+ },
+
+ setElementPrefixedProperty: function(element, property, value)
+ {
+ element.style[property] = element.style[this.browserPrefix().js + property[0].toUpperCase() + property.substr(1)] = value;
+ },
+
+ stripNonASCIICharacters: function(inputString)
+ {
+ return inputString.replace(/[ .,]/g, '');
+ },
+
+ convertObjectToQueryString: function(object)
+ {
+ var queryString = [];
+ for (var property in object) {
+ if (object.hasOwnProperty(property))
+ queryString.push(encodeURIComponent(property) + "=" + encodeURIComponent(object[property]));
+ }
+ return "?" + queryString.join("&");
+ },
+
+ convertQueryStringToObject: function(queryString)
+ {
+ queryString = queryString.substring(1);
+ if (!queryString)
+ return null;
+
+ var object = {};
+ queryString.split("&").forEach(function(parameter) {
+ var components = parameter.split("=");
+ object[components[0]] = components[1];
+ });
+ return object;
+ },
+
+ progressValue: function(value, min, max)
+ {
+ return (value - min) / (max - min);
+ },
+
+ lerp: function(value, min, max)
+ {
+ return min + (max - min) * value;
+ },
+
+ toFixedNumber: function(number, precision)
+ {
+ if (number.toFixed)
+ return Number(number.toFixed(precision));
+ return number;
+ }
+};
+
+Array.prototype.swap = function(i, j)
+{
+ var t = this[i];
+ this[i] = this[j];
+ this[j] = t;
+ return this;
+}
+
+if (!Array.prototype.fill) {
+ Array.prototype.fill = function(value) {
+ if (this == null)
+ throw new TypeError('Array.prototype.fill called on null or undefined');
+
+ var object = Object(this);
+ var len = parseInt(object.length, 10);
+ var start = arguments[1];
+ var relativeStart = parseInt(start, 10) || 0;
+ var k = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len);
+ var end = arguments[2];
+ var relativeEnd = end === undefined ? len : (parseInt(end) || 0) ;
+ var final = relativeEnd < 0 ? Math.max(len + relativeEnd, 0) : Math.min(relativeEnd, len);
+
+ for (; k < final; k++)
+ object[k] = value;
+
+ return object;
+ };
+}
+
+if (!Array.prototype.find) {
+ Array.prototype.find = function(predicate) {
+ if (this == null)
+ throw new TypeError('Array.prototype.find called on null or undefined');
+ if (typeof predicate !== 'function')
+ throw new TypeError('predicate must be a function');
+
+ var list = Object(this);
+ var length = list.length >>> 0;
+ var thisArg = arguments[1];
+ var value;
+
+ for (var i = 0; i < length; i++) {
+ value = list[i];
+ if (predicate.call(thisArg, value, i, list))
+ return value;
+ }
+ return undefined;
+ };
+}
+
+Array.prototype.shuffle = function()
+{
+ for (var index = this.length - 1; index >= 0; --index) {
+ var randomIndex = Math.floor(Math.random() * (index + 1));
+ this.swap(index, randomIndex);
+ }
+ return this;
+}
+
+Point = Utilities.createClass(
+ function(x, y)
+ {
+ this.x = x;
+ this.y = y;
+ }, {
+
+ // Used when the point object is used as a size object.
+ get width()
+ {
+ return this.x;
+ },
+
+ // Used when the point object is used as a size object.
+ get height()
+ {
+ return this.y;
+ },
+
+ // Used when the point object is used as a size object.
+ get center()
+ {
+ return new Point(this.x / 2, this.y / 2);
+ },
+
+ str: function()
+ {
+ return "x = " + this.x + ", y = " + this.y;
+ },
+
+ add: function(other)
+ {
+ if(isNaN(other.x))
+ return new Point(this.x + other, this.y + other);
+ return new Point(this.x + other.x, this.y + other.y);
+ },
+
+ subtract: function(other)
+ {
+ if(isNaN(other.x))
+ return new Point(this.x - other, this.y - other);
+ return new Point(this.x - other.x, this.y - other.y);
+ },
+
+ multiply: function(other)
+ {
+ if(isNaN(other.x))
+ return new Point(this.x * other, this.y * other);
+ return new Point(this.x * other.x, this.y * other.y);
+ },
+
+ move: function(angle, velocity, timeDelta)
+ {
+ return this.add(Point.pointOnCircle(angle, velocity * (timeDelta / 1000)));
+ },
+
+ length: function() {
+ return Math.sqrt( this.x * this.x + this.y * this.y );
+ },
+
+ normalize: function() {
+ var l = Math.sqrt( this.x * this.x + this.y * this.y );
+ this.x /= l;
+ this.y /= l;
+ return this;
+ }
+});
+
+Utilities.extendObject(Point, {
+ zero: new Point(0, 0),
+
+ pointOnCircle: function(angle, radius)
+ {
+ return new Point(radius * Math.cos(angle), radius * Math.sin(angle));
+ },
+
+ 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;
+ }, {
+
+ get width()
+ {
+ return this.left + this.right;
+ },
+
+ get height()
+ {
+ return this.top + this.bottom;
+ },
+
+ get size()
+ {
+ return new Point(this.width, this.height);
+ }
+});
+
+Insets.elementPadding = function(element)
+{
+ var styles = window.getComputedStyle(element);
+ return new Insets(
+ parseFloat(styles.paddingTop),
+ parseFloat(styles.paddingRight),
+ parseFloat(styles.paddingBottom),
+ parseFloat(styles.paddingTop));
+}
+
+UnitBezier = Utilities.createClass(
+ function(point1, point2)
+ {
+ // First and last points in the Bézier curve are assumed to be (0,0) and (!,1)
+ this._c = point1.multiply(3);
+ this._b = point2.subtract(point1).multiply(3).subtract(this._c);
+ this._a = new Point(1, 1).subtract(this._c).subtract(this._b);
+ }, {
+
+ epsilon: 1e-5,
+ derivativeEpsilon: 1e-6,
+
+ solve: function(x)
+ {
+ return this.sampleY(this.solveForT(x));
+ },
+
+ sampleX: function(t)
+ {
+ return ((this._a.x * t + this._b.x) * t + this._c.x) * t;
+ },
+
+ sampleY: function(t)
+ {
+ return ((this._a.y * t + this._b.y) * t + this._c.y) * t;
+ },
+
+ sampleDerivativeX: function(t)
+ {
+ return(3 * this._a.x * t + 2 * this._b.x) * t + this._c.x;
+ },
+
+ solveForT: function(x)
+ {
+ var t0, t1, t2, x2, d2, i;
+
+ for (t2 = x, i = 0; i < 8; ++i) {
+ x2 = this.sampleX(t2) - x;
+ if (Math.abs(x2) < this.epsilon)
+ return t2;
+ d2 = this.sampleDerivativeX(t2);
+ if (Math.abs(d2) < this.derivativeEpsilon)
+ break;
+ t2 = t2 - x2 / d2;
+ }
+
+ t0 = 0;
+ t1 = 1;
+ t2 = x;
+
+ if (t2 < t0)
+ return t0;
+ if (t2 > t1)
+ return t1;
+
+ while (t0 < t1) {
+ x2 = this.sampleX(t2);
+ if (Math.abs(x2 - x) < this.epsilon)
+ return t2;
+ if (x > x2)
+ t0 = t2;
+ else
+ t1 = t2;
+ t2 = (t1 - t0) * .5 + t0;
+ }
+
+ return t2;
+ }
+});
+
+SimplePromise = Utilities.createClass(
+ function()
+ {
+ this._chainedPromise = null;
+ this._callback = null;
+ }, {
+
+ then: function (callback)
+ {
+ if (this._callback)
+ throw "SimplePromise doesn't support multiple calls to then";
+
+ this._callback = callback;
+ this._chainedPromise = new SimplePromise;
+
+ if (this._resolved)
+ this.resolve(this._resolvedValue);
+
+ return this._chainedPromise;
+ },
+
+ resolve: function (value)
+ {
+ if (!this._callback) {
+ this._resolved = true;
+ this._resolvedValue = value;
+ return;
+ }
+
+ 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);
+ }
+});
+
+var Heap = Utilities.createClass(
+ function(maxSize, compare)
+ {
+ this._maxSize = maxSize;
+ this._compare = compare;
+ this._size = 0;
+ this._values = new Array(this._maxSize);
+ }, {
+
+ // This is a binary heap represented in an array. The root element is stored
+ // in the first element in the array. The root is followed by its two children.
+ // Then its four grandchildren and so on. So every level in the binary heap is
+ // doubled in the following level. Here is an example of the node indices and
+ // how they are related to their parents and children.
+ // ===========================================================================
+ // 0 1 2 3 4 5 6
+ // PARENT -1 0 0 1 1 2 2
+ // LEFT 1 3 5 7 9 11 13
+ // RIGHT 2 4 6 8 10 12 14
+ // ===========================================================================
+ _parentIndex: function(i)
+ {
+ return i > 0 ? Math.floor((i - 1) / 2) : -1;
+ },
+
+ _leftIndex: function(i)
+ {
+ var leftIndex = i * 2 + 1;
+ return leftIndex < this._size ? leftIndex : -1;
+ },
+
+ _rightIndex: function(i)
+ {
+ var rightIndex = i * 2 + 2;
+ return rightIndex < this._size ? rightIndex : -1;
+ },
+
+ // Return the child index that may violate the heap property at index i.
+ _childIndex: function(i)
+ {
+ var left = this._leftIndex(i);
+ var right = this._rightIndex(i);
+
+ if (left != -1 && right != -1)
+ return this._compare(this._values[left], this._values[right]) > 0 ? left : right;
+
+ return left != -1 ? left : right;
+ },
+
+ init: function()
+ {
+ this._size = 0;
+ },
+
+ top: function()
+ {
+ return this._size ? this._values[0] : NaN;
+ },
+
+ push: function(value)
+ {
+ if (this._size == this._maxSize) {
+ // If size is bounded and the new value can be a parent of the top()
+ // if the size were unbounded, just ignore the new value.
+ if (this._compare(value, this.top()) > 0)
+ return;
+ this.pop();
+ }
+ this._values[this._size++] = value;
+ this._bubble(this._size - 1);
+ },
+
+ pop: function()
+ {
+ if (!this._size)
+ return NaN;
+
+ this._values[0] = this._values[--this._size];
+ this._sink(0);
+ },
+
+ _bubble: function(i)
+ {
+ // Fix the heap property at index i given that parent is the only node that
+ // may violate the heap property.
+ for (var pi = this._parentIndex(i); pi != -1; i = pi, pi = this._parentIndex(pi)) {
+ if (this._compare(this._values[pi], this._values[i]) > 0)
+ break;
+
+ this._values.swap(pi, i);
+ }
+ },
+
+ _sink: function(i)
+ {
+ // Fix the heap property at index i given that each of the left and the right
+ // sub-trees satisfies the heap property.
+ for (var ci = this._childIndex(i); ci != -1; i = ci, ci = this._childIndex(ci)) {
+ if (this._compare(this._values[i], this._values[ci]) > 0)
+ break;
+
+ this._values.swap(ci, i);
+ }
+ },
+
+ str: function()
+ {
+ var out = "Heap[" + this._size + "] = [";
+ for (var i = 0; i < this._size; ++i) {
+ out += this._values[i];
+ if (i < this._size - 1)
+ out += ", ";
+ }
+ return out + "]";
+ },
+
+ values: function(size) {
+ // Return the last "size" heap elements values.
+ var values = this._values.slice(0, this._size);
+ return values.sort(this._compare).slice(0, Math.min(size, this._size));
+ }
+});
+
+Utilities.extendObject(Heap, {
+ createMinHeap: function(maxSize)
+ {
+ return new Heap(maxSize, function(a, b) { return b - a; });
+ },
+
+ createMaxHeap: function(maxSize) {
+ return new Heap(maxSize, function(a, b) { return a - b; });
+ }
+});
+
+var SampleData = Utilities.createClass(
+ function(fieldMap, data)
+ {
+ this.fieldMap = fieldMap || {};
+ this.data = data || [];
+ }, {
+
+ get length()
+ {
+ return this.data.length;
+ },
+
+ addField: function(name, index)
+ {
+ this.fieldMap[name] = index;
+ },
+
+ push: function(datum)
+ {
+ this.data.push(datum);
+ },
+
+ sort: function(sortFunction)
+ {
+ this.data.sort(sortFunction);
+ },
+
+ slice: function(begin, end)
+ {
+ return new SampleData(this.fieldMap, this.data.slice(begin, end));
+ },
+
+ forEach: function(iterationFunction)
+ {
+ this.data.forEach(iterationFunction);
+ },
+
+ createDatum: function()
+ {
+ return [];
+ },
+
+ getFieldInDatum: function(datum, fieldName)
+ {
+ if (typeof datum === 'number')
+ datum = this.data[datum];
+ return datum[this.fieldMap[fieldName]];
+ },
+
+ setFieldInDatum: function(datum, fieldName, value)
+ {
+ if (typeof datum === 'number')
+ datum = this.data[datum];
+ return datum[this.fieldMap[fieldName]] = value;
+ },
+
+ at: function(index)
+ {
+ return this.data[index];
+ },
+
+ toArray: function()
+ {
+ var array = [];
+
+ this.data.forEach(function(datum) {
+ var newDatum = {};
+ array.push(newDatum);
+
+ for (var fieldName in this.fieldMap) {
+ var value = this.getFieldInDatum(datum, fieldName);
+ if (value !== null && value !== undefined)
+ newDatum[fieldName] = value;
+ }
+ }, this);
+
+ return array;
+ }
+});
diff --git a/third_party/webkit/PerformanceTests/MotionMark/resources/runner/animometer.css b/third_party/webkit/PerformanceTests/MotionMark/resources/runner/animometer.css
new file mode 100644
index 0000000000..86da6bea1c
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/resources/runner/animometer.css
@@ -0,0 +1,520 @@
+/* Outer harness */
+
+html,
+body {
+ min-height: 100%;
+}
+
+body {
+ background-color: hsl(0, 0%, 95%);
+
+ font-family: "Helvetica Neue", Helvetica, Verdana, sans-serif;
+ font-size: 15px;
+
+ cursor: default;
+
+ -webkit-user-select: none;
+}
+
+body.showing-intro,
+body.showing-results {
+ background-color: hsl(35, 100%, 100%);
+ background-image: url(crystal.svg), url(lines.svg);
+ background-size: auto 225%, auto 100%;
+ background-repeat: no-repeat;
+
+ animation: background-fade 1s ease-in 1s, background-color 60s linear infinite 2s;
+ animation-play-state: paused;
+
+ will-change: background-color;
+}
+
+body.showing-test-container {
+ overflow: hidden;
+}
+
+body.images-loaded {
+ animation-play-state: running;
+}
+
+@media screen and (min-width: 667px) {
+ body {
+ font-size: 24px;
+ }
+
+ body.showing-intro,
+ body.showing-results {
+ background-size: 200% 100%, 150% auto;
+ }
+}
+
+@media screen and (min-width: 1025px) {
+ body.showing-intro,
+ body.showing-results {
+ background-size: 150% 100%, 150% auto;
+ }
+}
+
+::selection {
+ background-color: black;
+ color: white;
+}
+
+.hidden {
+ display: none;
+}
+
+section {
+ display: none;
+}
+
+section.selected {
+ display: block;
+}
+
+svg.logo {
+ width: 350px;
+ height: 88px;
+
+ max-width: 100%;
+
+ padding-bottom: 1em;
+
+ color: hsl(35, 100%, 50%);
+
+ animation: foreground-color 60s linear infinite 2s;
+ animation-play-state: paused;
+
+ will-change: color;
+}
+
+body.images-loaded svg.logo {
+ animation-play-state: running;
+}
+
+@media screen and (min-width: 667px) {
+ svg.logo {
+ width: 525px;
+ height: 130px;
+ }
+}
+
+section .body {
+ margin: 0 1em;
+ max-width: 350px;
+}
+
+section .body p {
+ margin: 1em 0;
+ line-height: 1.5em;
+
+ -webkit-user-select: text;
+ cursor: text;
+}
+
+@media screen and (min-width: 667px) {
+ section .body {
+ margin-left: 2.5em;
+ max-width: 500px;
+ transform: skewX(-10deg);
+ }
+
+ section button {
+ transform: none;
+ }
+}
+
+button {
+ background-color: hsl(35, 100%, 50%);
+ color: white;
+
+ padding: 0.25em;
+ margin: 1.5em -0.25em 0 0;
+
+ min-width: 50%;
+
+ border: none;
+
+ font-family: inherit;
+ font-size: inherit;
+
+ transform: skewX(-10deg);
+
+ transition: 100ms filter ease-in-out;
+
+ animation: background-color 60s linear infinite 2s;
+ animation-play-state: paused;
+
+ will-change: background-color;
+}
+
+body.images-loaded button {
+ animation-play-state: running;
+}
+
+button:hover {
+ filter: brightness(115%);
+}
+
+button:active {
+ filter: brightness(130%);
+}
+
+button:disabled {
+ opacity: 0.5;
+ filter: none !important;
+}
+
+@media print {
+ button {
+ display: none;
+ }
+}
+
+.portrait-orientation-check {
+ display: none;
+}
+
+@media screen and (max-device-width: 1025px) and (orientation: portrait) {
+ .portrait-orientation-check {
+ display: block;
+ }
+}
+
+@media screen and (max-device-width: 1025px) and (orientation: portrait) {
+ .landscape-orientation-check {
+ /* This keeps the button color animation in sync with page, while display: none does not. */
+ visibility: hidden;
+ }
+}
+
+@keyframes background-fade {
+ 100% {
+ background-color: hsl(35, 100%, 50%);
+ }
+}
+
+@keyframes background-color {
+ 0%, 10% {
+ background-color: hsl(35, 100%, 50%);
+ }
+
+ 12%, 20% {
+ background-color: hsl(75, 100%, 30%);
+ }
+
+ 22%, 30% {
+ background-color: hsl(115, 100%, 30%);
+ }
+
+ 32%, 40% {
+ background-color: hsl(155, 100%, 30%);
+ }
+
+ 42%, 50% {
+ background-color: hsl(195, 100%, 30%);
+ }
+
+ 52%, 60% {
+ background-color: hsl(235, 100%, 30%);
+ }
+
+ 62%, 70% {
+ background-color: hsl(275, 100%, 30%);
+ }
+
+ 72%, 80% {
+ background-color: hsl(315, 100%, 30%);
+ }
+
+ 82%, 90% {
+ background-color: hsl(355, 100%, 30%);
+ }
+
+ 92%, 100% {
+ background-color: hsl(395, 100%, 50%);
+ }
+}
+
+@keyframes foreground-color {
+ 0%, 10% {
+ color: hsl(35, 100%, 50%);
+ }
+
+ 12%, 20% {
+ color: hsl(75, 100%, 30%);
+ }
+
+ 22%, 30% {
+ color: hsl(115, 100%, 30%);
+ }
+
+ 32%, 40% {
+ color: hsl(155, 100%, 30%);
+ }
+
+ 42%, 50% {
+ color: hsl(195, 100%, 30%);
+ }
+
+ 52%, 60% {
+ color: hsl(235, 100%, 30%);
+ }
+
+ 62%, 70% {
+ color: hsl(275, 100%, 30%);
+ }
+
+ 72%, 80% {
+ color: hsl(315, 100%, 30%);
+ }
+
+ 82%, 90% {
+ color: hsl(355, 100%, 30%);
+ }
+
+ 92%, 100% {
+ color: hsl(395, 100%, 50%);
+ }
+}
+
+/* Intro section, About page */
+
+#intro, #about {
+ padding: 2em;
+}
+
+#intro {
+ opacity: 0;
+ transition: opacity 500ms ease-in;
+}
+
+body.images-loaded #intro {
+ opacity: 1;
+}
+
+#about .body {
+ transform: none;
+ margin: 0;
+ max-width: initial;
+}
+
+#about li {
+ line-height: 1.5em;
+}
+
+#about button {
+ padding: .75em 2em;
+ margin: 1.5em auto 0;
+ min-width: initial;
+ transform: skewX(-10deg);
+}
+
+@media screen and (min-width: 667px) {
+ #about .body {
+ font-size: .7em;
+ margin: 1em;
+ }
+
+ #about ol, #about ul {
+ padding-left: 3em;
+ }
+}
+
+
+#intro a, #about a,
+#intro a:visited, #about a:visited {
+ color: black;
+}
+
+/* Running test section */
+
+.frame-container {
+ position: absolute;
+
+ top: 50%;
+ left: 50%;
+}
+
+.frame-container > iframe {
+ width: 100%;
+ height: 100%;
+
+ border: 0;
+ margin: 0;
+}
+
+body.small .frame-container {
+ width: 568px;
+ height: 320px;
+ margin-left: -284px;
+ margin-top: -160px;
+}
+
+body.medium .frame-container {
+ width: 900px;
+ height: 600px;
+ margin-left: -450px;
+ margin-top: -300px;
+}
+
+body.large .frame-container {
+ width: 1600px;
+ height: 800px;
+ margin-left: -800px;
+ margin-top: -400px;
+}
+
+/* Results section */
+
+#results {
+ padding: 2em;
+}
+
+#results .body {
+ -webkit-user-select: text;
+}
+
+#results .score-container {
+ padding-bottom: 2em;
+}
+
+#results .table-container {
+ position: relative;
+}
+
+#results .table-container > div {
+ margin-left: 40%;
+}
+
+#results .score {
+ font-size: 5em;
+ font-weight: bold;
+ font-style: italic;
+ line-height: 1;
+ margin: 0;
+}
+
+#results .confidence {
+ font-size: 2em;
+ font-style: italic;
+ line-height: 1;
+ margin: 0;
+ text-indent: 1.75em;
+ color: hsl(0, 0%, 40%);
+ padding-bottom: .3em;
+}
+
+#results table {
+ border-spacing: 0;
+ margin: 0;
+ padding: 0;
+ min-width: 25%;
+}
+
+#results table td,
+#results table th {
+ padding: 0.25em;
+}
+
+#results table td.suites-separator {
+ padding: 0;
+}
+
+#results table tr:nth-child(even) {
+ background-color: hsla(0, 0%, 0%, 0.05);
+}
+
+#results #results-header {
+ top: 0;
+ left: 0;
+ width: 40%;
+ position: absolute;
+}
+
+#results #results-score {
+ float: left;
+}
+
+#results #results-data span {
+ font-size: .75em;
+ color: hsl(0, 0%, 40%);
+}
+
+#results #results-header td,
+#results #results-header th {
+ text-align: right;
+ padding-right: 1em !important;
+ padding-left: 0.5em !important;
+}
+
+#results #results-score td,
+#results #results-score th {
+ text-align: left;
+ padding-right: 0.5em !important;
+}
+
+#results #results-score td {
+ cursor: text;
+}
+
+@media screen and (min-width: 667px) {
+ #results .score,
+ #results .confidence {
+ font-style: normal;
+ }
+}
+
+.detail span {
+ display: none;
+}
+
+body.small .detail .small,
+body.medium .detail .medium,
+body.large .detail .large {
+ display: initial;
+}
+
+#overlay {
+ position: fixed;
+
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+
+ background: hsla(0, 0%, 100%, 0.9);
+}
+
+@supports (-webkit-backdrop-filter: blur(10px)) {
+ #overlay {
+ background: hsla(0, 0%, 100%, 0.7);
+ -webkit-backdrop-filter: blur(20px);
+ }
+}
+
+#overlay > div {
+ position: absolute;
+
+ width: 500px;
+ height: 500px;
+
+ margin-top: -250px;
+ margin-left: -250px;
+
+ top: 50%;
+ left: 50%;
+}
+
+#overlay > div div {
+ overflow: scroll;
+
+ font-size: 12px;
+ -webkit-user-select: text;
+ cursor: text;
+
+ max-height: 250px;
+
+ border: 1px solid hsla(0, 0%, 0%, 0.1);
+ padding: 1em;
+}
diff --git a/third_party/webkit/PerformanceTests/MotionMark/resources/runner/animometer.js b/third_party/webkit/PerformanceTests/MotionMark/resources/runner/animometer.js
new file mode 100644
index 0000000000..65e8c5450d
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/resources/runner/animometer.js
@@ -0,0 +1,626 @@
+ResultsDashboard = Utilities.createClass(
+ function(options, testData)
+ {
+ this._iterationsSamplers = [];
+ this._options = options;
+ this._results = null;
+ if (testData) {
+ this._iterationsSamplers = testData;
+ this._processData();
+ }
+ }, {
+
+ push: function(suitesSamplers)
+ {
+ this._iterationsSamplers.push(suitesSamplers);
+ },
+
+ _processData: function()
+ {
+ this._results = {};
+ this._results[Strings.json.results.iterations] = [];
+
+ var iterationsScores = [];
+ this._iterationsSamplers.forEach(function(iteration, index) {
+ var testsScores = [];
+ var testsLowerBoundScores = [];
+ var testsUpperBoundScores = [];
+
+ var result = {};
+ this._results[Strings.json.results.iterations][index] = result;
+
+ var suitesResult = {};
+ result[Strings.json.results.tests] = suitesResult;
+
+ for (var suiteName in iteration) {
+ var suiteData = iteration[suiteName];
+
+ var suiteResult = {};
+ suitesResult[suiteName] = suiteResult;
+
+ for (var testName in suiteData) {
+ if (!suiteData[testName][Strings.json.result])
+ this.calculateScore(suiteData[testName]);
+
+ suiteResult[testName] = suiteData[testName][Strings.json.result];
+ delete suiteData[testName][Strings.json.result];
+
+ testsScores.push(suiteResult[testName][Strings.json.score]);
+ testsLowerBoundScores.push(suiteResult[testName][Strings.json.scoreLowerBound]);
+ testsUpperBoundScores.push(suiteResult[testName][Strings.json.scoreUpperBound]);
+ }
+ }
+
+ result[Strings.json.score] = Statistics.geometricMean(testsScores);
+ result[Strings.json.scoreLowerBound] = Statistics.geometricMean(testsLowerBoundScores);
+ result[Strings.json.scoreUpperBound] = Statistics.geometricMean(testsUpperBoundScores);
+ iterationsScores.push(result[Strings.json.score]);
+ }, this);
+
+ this._results[Strings.json.score] = Statistics.sampleMean(iterationsScores.length, iterationsScores.reduce(function(a, b) { return a + b; }));
+ this._results[Strings.json.scoreLowerBound] = this._results[Strings.json.results.iterations][0][Strings.json.scoreLowerBound];
+ this._results[Strings.json.scoreUpperBound] = this._results[Strings.json.results.iterations][0][Strings.json.scoreUpperBound];
+ },
+
+ calculateScore: function(data)
+ {
+ var result = {};
+ data[Strings.json.result] = result;
+ var samples = data[Strings.json.samples];
+
+ var desiredFrameLength = 1000/60;
+ if (this._options["controller"] == "ramp30")
+ desiredFrameLength = 1000/30;
+
+ function findRegression(series, profile) {
+ var minIndex = Math.round(.025 * series.length);
+ var maxIndex = Math.round(.975 * (series.length - 1));
+ var minComplexity = series.getFieldInDatum(minIndex, Strings.json.complexity);
+ var maxComplexity = series.getFieldInDatum(maxIndex, Strings.json.complexity);
+
+ if (Math.abs(maxComplexity - minComplexity) < 20 && maxIndex - minIndex < 20) {
+ minIndex = 0;
+ maxIndex = series.length - 1;
+ minComplexity = series.getFieldInDatum(minIndex, Strings.json.complexity);
+ maxComplexity = series.getFieldInDatum(maxIndex, Strings.json.complexity);
+ }
+
+ var complexityIndex = series.fieldMap[Strings.json.complexity];
+ var frameLengthIndex = series.fieldMap[Strings.json.frameLength];
+ var regressionOptions = { desiredFrameLength: desiredFrameLength };
+ if (profile)
+ regressionOptions.preferredProfile = profile;
+ return {
+ minComplexity: minComplexity,
+ maxComplexity: maxComplexity,
+ samples: series.slice(minIndex, maxIndex + 1),
+ regression: new Regression(
+ series.data,
+ function (data, i) { return data[i][complexityIndex]; },
+ function (data, i) { return data[i][frameLengthIndex]; },
+ minIndex, maxIndex, regressionOptions)
+ };
+ }
+
+ var complexitySamples;
+ // Convert these samples into SampleData objects if needed
+ [Strings.json.complexity, Strings.json.complexityAverage, Strings.json.controller].forEach(function(seriesName) {
+ var series = samples[seriesName];
+ if (series && !(series instanceof SampleData))
+ samples[seriesName] = new SampleData(series.fieldMap, series.data);
+ });
+
+ var isRampController = ["ramp", "ramp30"].indexOf(this._options["controller"]) != -1;
+ var predominantProfile = "";
+ if (isRampController) {
+ var profiles = {};
+ data[Strings.json.controller].forEach(function(regression) {
+ if (regression[Strings.json.regressions.profile]) {
+ var profile = regression[Strings.json.regressions.profile];
+ profiles[profile] = (profiles[profile] || 0) + 1;
+ }
+ });
+
+ var maxProfileCount = 0;
+ for (var profile in profiles) {
+ if (profiles[profile] > maxProfileCount) {
+ predominantProfile = profile;
+ maxProfileCount = profiles[profile];
+ }
+ }
+ }
+
+ [Strings.json.complexity, Strings.json.complexityAverage].forEach(function(seriesName) {
+ if (!(seriesName in samples))
+ return;
+
+ var regression = {};
+ result[seriesName] = regression;
+ var regressionResult = findRegression(samples[seriesName], predominantProfile);
+ if (seriesName == Strings.json.complexity)
+ complexitySamples = regressionResult.samples;
+ var calculation = regressionResult.regression;
+ regression[Strings.json.regressions.segment1] = [
+ [regressionResult.minComplexity, calculation.s1 + calculation.t1 * regressionResult.minComplexity],
+ [calculation.complexity, calculation.s1 + calculation.t1 * calculation.complexity]
+ ];
+ regression[Strings.json.regressions.segment2] = [
+ [calculation.complexity, calculation.s2 + calculation.t2 * calculation.complexity],
+ [regressionResult.maxComplexity, calculation.s2 + calculation.t2 * regressionResult.maxComplexity]
+ ];
+ regression[Strings.json.complexity] = calculation.complexity;
+ regression[Strings.json.measurements.stdev] = Math.sqrt(calculation.error / samples[seriesName].length);
+ });
+
+ if (isRampController) {
+ var timeComplexity = new Experiment;
+ data[Strings.json.controller].forEach(function(regression) {
+ timeComplexity.sample(regression[Strings.json.complexity]);
+ });
+
+ var experimentResult = {};
+ result[Strings.json.controller] = experimentResult;
+ experimentResult[Strings.json.score] = timeComplexity.mean();
+ experimentResult[Strings.json.measurements.average] = timeComplexity.mean();
+ experimentResult[Strings.json.measurements.stdev] = timeComplexity.standardDeviation();
+ experimentResult[Strings.json.measurements.percent] = timeComplexity.percentage();
+
+ const bootstrapIterations = 2500;
+ var bootstrapResult = Regression.bootstrap(complexitySamples.data, bootstrapIterations, function(resampleData) {
+ var complexityIndex = complexitySamples.fieldMap[Strings.json.complexity];
+ resampleData.sort(function(a, b) {
+ return a[complexityIndex] - b[complexityIndex];
+ });
+
+ var resample = new SampleData(complexitySamples.fieldMap, resampleData);
+ var regressionResult = findRegression(resample, predominantProfile);
+ return regressionResult.regression.complexity;
+ }, .8);
+
+ result[Strings.json.complexity][Strings.json.bootstrap] = bootstrapResult;
+ result[Strings.json.score] = bootstrapResult.median;
+ result[Strings.json.scoreLowerBound] = bootstrapResult.confidenceLow;
+ result[Strings.json.scoreUpperBound] = bootstrapResult.confidenceHigh;
+ } else {
+ var marks = data[Strings.json.marks];
+ var samplingStartIndex = 0, samplingEndIndex = -1;
+ if (Strings.json.samplingStartTimeOffset in marks)
+ samplingStartIndex = marks[Strings.json.samplingStartTimeOffset].index;
+ if (Strings.json.samplingEndTimeOffset in marks)
+ samplingEndIndex = marks[Strings.json.samplingEndTimeOffset].index;
+
+ var averageComplexity = new Experiment;
+ var averageFrameLength = new Experiment;
+ var controllerSamples = samples[Strings.json.controller];
+ controllerSamples.forEach(function (sample, i) {
+ if (i >= samplingStartIndex && (samplingEndIndex == -1 || i < samplingEndIndex)) {
+ averageComplexity.sample(controllerSamples.getFieldInDatum(sample, Strings.json.complexity));
+ var smoothedFrameLength = controllerSamples.getFieldInDatum(sample, Strings.json.smoothedFrameLength);
+ if (smoothedFrameLength && smoothedFrameLength != -1)
+ averageFrameLength.sample(smoothedFrameLength);
+ }
+ });
+
+ var experimentResult = {};
+ result[Strings.json.controller] = experimentResult;
+ experimentResult[Strings.json.measurements.average] = averageComplexity.mean();
+ experimentResult[Strings.json.measurements.concern] = averageComplexity.concern(Experiment.defaults.CONCERN);
+ experimentResult[Strings.json.measurements.stdev] = averageComplexity.standardDeviation();
+ experimentResult[Strings.json.measurements.percent] = averageComplexity.percentage();
+
+ experimentResult = {};
+ result[Strings.json.frameLength] = experimentResult;
+ experimentResult[Strings.json.measurements.average] = 1000 / averageFrameLength.mean();
+ experimentResult[Strings.json.measurements.concern] = averageFrameLength.concern(Experiment.defaults.CONCERN);
+ experimentResult[Strings.json.measurements.stdev] = averageFrameLength.standardDeviation();
+ experimentResult[Strings.json.measurements.percent] = averageFrameLength.percentage();
+
+ result[Strings.json.score] = averageComplexity.score(Experiment.defaults.CONCERN);
+ result[Strings.json.scoreLowerBound] = result[Strings.json.score] - averageFrameLength.standardDeviation();
+ result[Strings.json.scoreUpperBound] = result[Strings.json.score] + averageFrameLength.standardDeviation();
+ }
+ },
+
+ get data()
+ {
+ return this._iterationsSamplers;
+ },
+
+ get results()
+ {
+ if (this._results)
+ return this._results[Strings.json.results.iterations];
+ this._processData();
+ return this._results[Strings.json.results.iterations];
+ },
+
+ get options()
+ {
+ return this._options;
+ },
+
+ _getResultsProperty: function(property)
+ {
+ if (this._results)
+ return this._results[property];
+ this._processData();
+ return this._results[property];
+ },
+
+ get score()
+ {
+ return this._getResultsProperty(Strings.json.score);
+ },
+
+ get scoreLowerBound()
+ {
+ return this._getResultsProperty(Strings.json.scoreLowerBound);
+ },
+
+ get scoreUpperBound()
+ {
+ return this._getResultsProperty(Strings.json.scoreUpperBound);
+ }
+});
+
+ResultsTable = Utilities.createClass(
+ function(element, headers)
+ {
+ this.element = element;
+ this._headers = headers;
+
+ this._flattenedHeaders = [];
+ this._headers.forEach(function(header) {
+ if (header.disabled)
+ return;
+
+ if (header.children)
+ this._flattenedHeaders = this._flattenedHeaders.concat(header.children);
+ else
+ this._flattenedHeaders.push(header);
+ }, this);
+
+ this._flattenedHeaders = this._flattenedHeaders.filter(function (header) {
+ return !header.disabled;
+ });
+
+ this.clear();
+ }, {
+
+ clear: function()
+ {
+ this.element.textContent = "";
+ },
+
+ _addHeader: function()
+ {
+ var thead = Utilities.createElement("thead", {}, this.element);
+ var row = Utilities.createElement("tr", {}, thead);
+
+ this._headers.forEach(function (header) {
+ if (header.disabled)
+ return;
+
+ var th = Utilities.createElement("th", {}, row);
+ if (header.title != Strings.text.graph)
+ th.innerHTML = header.title;
+ if (header.children)
+ th.colSpan = header.children.length;
+ });
+ },
+
+ _addBody: function()
+ {
+ this.tbody = Utilities.createElement("tbody", {}, this.element);
+ },
+
+ _addEmptyRow: function()
+ {
+ var row = Utilities.createElement("tr", {}, this.tbody);
+ this._flattenedHeaders.forEach(function (header) {
+ return Utilities.createElement("td", { class: "suites-separator" }, row);
+ });
+ },
+
+ _addTest: function(testName, testResult, options)
+ {
+ var row = Utilities.createElement("tr", {}, this.tbody);
+
+ this._flattenedHeaders.forEach(function (header) {
+ var td = Utilities.createElement("td", {}, row);
+ if (header.text == Strings.text.testName) {
+ td.textContent = testName;
+ } else if (typeof header.text == "string") {
+ var data = testResult[header.text];
+ if (typeof data == "number")
+ data = data.toFixed(2);
+ td.innerHTML = data;
+ } else
+ td.innerHTML = header.text(testResult);
+ }, this);
+ },
+
+ _addIteration: function(iterationResult, iterationData, options)
+ {
+ var testsResults = iterationResult[Strings.json.results.tests];
+ for (var suiteName in testsResults) {
+ this._addEmptyRow();
+ var suiteResult = testsResults[suiteName];
+ var suiteData = iterationData[suiteName];
+ for (var testName in suiteResult)
+ this._addTest(testName, suiteResult[testName], options, suiteData[testName]);
+ }
+ },
+
+ showIterations: function(dashboard)
+ {
+ this.clear();
+ this._addHeader();
+ this._addBody();
+
+ var iterationsResults = dashboard.results;
+ iterationsResults.forEach(function(iterationResult, index) {
+ this._addIteration(iterationResult, dashboard.data[index], dashboard.options);
+ }, this);
+ }
+});
+
+window.benchmarkRunnerClient = {
+ iterationCount: 1,
+ options: null,
+ results: null,
+
+ initialize: function(suites, options)
+ {
+ this.options = options;
+ },
+
+ willStartFirstIteration: function()
+ {
+ this.results = new ResultsDashboard(this.options);
+ },
+
+ didRunSuites: function(suitesSamplers)
+ {
+ this.results.push(suitesSamplers);
+ },
+
+ didRunTest: function(testData)
+ {
+ this.results.calculateScore(testData);
+ },
+
+ didFinishLastIteration: function()
+ {
+ benchmarkController.showResults();
+ }
+};
+
+window.sectionsManager =
+{
+ showSection: function(sectionIdentifier, pushState)
+ {
+ var sections = document.querySelectorAll("main > section");
+ for (var i = 0; i < sections.length; ++i) {
+ document.body.classList.remove("showing-" + sections[i].id);
+ }
+ document.body.classList.add("showing-" + sectionIdentifier);
+
+ var currentSectionElement = document.querySelector("section.selected");
+ console.assert(currentSectionElement);
+
+ var newSectionElement = document.getElementById(sectionIdentifier);
+ console.assert(newSectionElement);
+
+ currentSectionElement.classList.remove("selected");
+ newSectionElement.classList.add("selected");
+
+ if (pushState)
+ history.pushState({section: sectionIdentifier}, document.title);
+ },
+
+ setSectionScore: function(sectionIdentifier, score, confidence)
+ {
+ document.querySelector("#" + sectionIdentifier + " .score").textContent = score;
+ if (confidence)
+ document.querySelector("#" + sectionIdentifier + " .confidence").textContent = confidence;
+ },
+
+ populateTable: function(tableIdentifier, headers, dashboard)
+ {
+ var table = new ResultsTable(document.getElementById(tableIdentifier), headers);
+ table.showIterations(dashboard);
+ }
+};
+
+window.benchmarkController = {
+ initialize: function()
+ {
+ benchmarkController.addOrientationListenerIfNecessary();
+ },
+
+ determineCanvasSize: function() {
+ var match = window.matchMedia("(max-device-width: 760px)");
+ if (match.matches) {
+ document.body.classList.add("small");
+ return;
+ }
+
+ match = window.matchMedia("(max-device-width: 1600px)");
+ if (match.matches) {
+ document.body.classList.add("medium");
+ return;
+ }
+
+ match = window.matchMedia("(max-width: 1600px)");
+ if (match.matches) {
+ document.body.classList.add("medium");
+ return;
+ }
+
+ document.body.classList.add("large");
+ },
+
+ addOrientationListenerIfNecessary: function() {
+ if (!("orientation" in window))
+ return;
+
+ this.orientationQuery = window.matchMedia("(orientation: landscape)");
+ this._orientationChanged(this.orientationQuery);
+ this.orientationQuery.addListener(this._orientationChanged);
+ },
+
+ _orientationChanged: function(match)
+ {
+ benchmarkController.isInLandscapeOrientation = match.matches;
+ if (match.matches)
+ document.querySelector(".start-benchmark p").classList.add("hidden");
+ else
+ document.querySelector(".start-benchmark p").classList.remove("hidden");
+ benchmarkController.updateStartButtonState();
+ },
+
+ updateStartButtonState: function()
+ {
+ document.getElementById("run-benchmark").disabled = !this.isInLandscapeOrientation;
+ },
+
+ _startBenchmark: function(suites, options, frameContainerID)
+ {
+ benchmarkController.determineCanvasSize();
+
+ var configuration = document.body.className.match(/small|medium|large/);
+ if (configuration)
+ options[Strings.json.configuration] = configuration[0];
+
+ benchmarkRunnerClient.initialize(suites, options);
+ var frameContainer = document.getElementById(frameContainerID);
+ var runner = new BenchmarkRunner(suites, frameContainer, benchmarkRunnerClient);
+ runner.runMultipleIterations();
+
+ sectionsManager.showSection("test-container");
+ },
+
+ startBenchmark: function()
+ {
+ var options = {
+ "test-interval": 30,
+ "display": "minimal",
+ "tiles": "big",
+ "controller": "ramp",
+ "kalman-process-error": 1,
+ "kalman-measurement-error": 4,
+ "time-measurement": "performance"
+ };
+ this._startBenchmark(Suites, options, "test-container");
+ },
+
+ showResults: function()
+ {
+ if (!this.addedKeyEvent) {
+ document.addEventListener("keypress", this.handleKeyPress, false);
+ this.addedKeyEvent = true;
+ }
+
+ var dashboard = benchmarkRunnerClient.results;
+ var score = dashboard.score;
+ var confidence = "±" + (Statistics.largestDeviationPercentage(dashboard.scoreLowerBound, score, dashboard.scoreUpperBound) * 100).toFixed(2) + "%";
+ sectionsManager.setSectionScore("results", score.toFixed(2), confidence);
+ sectionsManager.populateTable("results-header", Headers.testName, dashboard);
+ sectionsManager.populateTable("results-score", Headers.score, dashboard);
+ sectionsManager.populateTable("results-data", Headers.details, dashboard);
+ sectionsManager.showSection("results", true);
+ },
+
+ handleKeyPress: function(event)
+ {
+ switch (event.charCode)
+ {
+ case 27: // esc
+ benchmarkController.hideDebugInfo();
+ break;
+ case 106: // j
+ benchmarkController.showDebugInfo();
+ break;
+ case 115: // s
+ benchmarkController.selectResults(event.target);
+ break;
+ }
+ },
+
+ hideDebugInfo: function()
+ {
+ var overlay = document.getElementById("overlay");
+ if (!overlay)
+ return;
+ document.body.removeChild(overlay);
+ },
+
+ showDebugInfo: function()
+ {
+ if (document.getElementById("overlay"))
+ return;
+
+ var overlay = Utilities.createElement("div", {
+ id: "overlay"
+ }, document.body);
+ var container = Utilities.createElement("div", {}, overlay);
+
+ var header = Utilities.createElement("h3", {}, container);
+ header.textContent = "Debug Output";
+
+ var data = Utilities.createElement("div", {}, container);
+ data.textContent = "Please wait...";
+ setTimeout(function() {
+ var output = {
+ options: benchmarkRunnerClient.results.options,
+ data: benchmarkRunnerClient.results.data
+ };
+ data.textContent = JSON.stringify(output, function(key, value) {
+ if (typeof value === 'number')
+ return Utilities.toFixedNumber(value, 3);
+ return value;
+ }, 1);
+ }, 0);
+ data.onclick = function() {
+ var selection = window.getSelection();
+ selection.removeAllRanges();
+ var range = document.createRange();
+ range.selectNode(data);
+ selection.addRange(range);
+ };
+
+ var button = Utilities.createElement("button", {}, container);
+ button.textContent = "Done";
+ button.onclick = function() {
+ benchmarkController.hideDebugInfo();
+ };
+ },
+
+ selectResults: function(target)
+ {
+ target.selectRange = ((target.selectRange || 0) + 1) % 3;
+
+ var selection = window.getSelection();
+ selection.removeAllRanges();
+ var range = document.createRange();
+ switch (target.selectRange) {
+ case 0: {
+ range.selectNode(document.getElementById("results-score"));
+ break;
+ }
+ case 1: {
+ range.setStart(document.querySelector("#results .score"), 0);
+ range.setEndAfter(document.querySelector("#results-score"), 0);
+ break;
+ }
+ case 2: {
+ range.selectNodeContents(document.querySelector("#results .score"));
+ break;
+ }
+ }
+ selection.addRange(range);
+ }
+};
+
+window.addEventListener("load", function() { benchmarkController.initialize(); });
diff --git a/third_party/webkit/PerformanceTests/MotionMark/resources/runner/benchmark-runner.js b/third_party/webkit/PerformanceTests/MotionMark/resources/runner/benchmark-runner.js
new file mode 100644
index 0000000000..1aa630356c
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/resources/runner/benchmark-runner.js
@@ -0,0 +1,179 @@
+BenchmarkRunnerState = Utilities.createClass(
+ function(suites)
+ {
+ this._suites = suites;
+ this._suiteIndex = -1;
+ this._testIndex = 0;
+ this.next();
+ }, {
+
+ currentSuite: function()
+ {
+ return this._suites[this._suiteIndex];
+ },
+
+ currentTest: function()
+ {
+ var suite = this.currentSuite();
+ return suite ? suite.tests[this._testIndex] : null;
+ },
+
+ isFirstTest: function()
+ {
+ return !this._testIndex;
+ },
+
+ next: function()
+ {
+ this._testIndex++;
+
+ var suite = this._suites[this._suiteIndex];
+ if (suite && this._testIndex < suite.tests.length)
+ return;
+
+ this._testIndex = 0;
+ do {
+ this._suiteIndex++;
+ } while (this._suiteIndex < this._suites.length && this._suites[this._suiteIndex].disabled);
+ },
+
+ prepareCurrentTest: function(runner, frame)
+ {
+ var test = this.currentTest();
+ var promise = new SimplePromise;
+
+ frame.onload = function() {
+ promise.resolve();
+ };
+
+ frame.src = "tests/" + test.url;
+ return promise;
+ }
+});
+
+BenchmarkRunner = Utilities.createClass(
+ function(suites, frameContainer, client)
+ {
+ this._suites = suites;
+ this._client = client;
+ this._frameContainer = frameContainer;
+ }, {
+
+ _appendFrame: function()
+ {
+ var frame = document.createElement("iframe");
+ frame.setAttribute("scrolling", "no");
+
+ this._frameContainer.insertBefore(frame, this._frameContainer.firstChild);
+ this._frame = frame;
+ return frame;
+ },
+
+ _removeFrame: function()
+ {
+ if (this._frame) {
+ this._frame.parentNode.removeChild(this._frame);
+ this._frame = null;
+ }
+ },
+
+ _runBenchmarkAndRecordResults: function(state)
+ {
+ var promise = new SimplePromise;
+ var suite = state.currentSuite();
+ var test = state.currentTest();
+
+ if (this._client && this._client.willRunTest)
+ this._client.willRunTest(suite, test);
+
+ var contentWindow = this._frame.contentWindow;
+ var self = this;
+
+ var options = { complexity: test.complexity };
+ Utilities.extendObject(options, this._client.options);
+ Utilities.extendObject(options, contentWindow.Utilities.parseParameters());
+
+ var benchmark = new contentWindow.benchmarkClass(options);
+ document.body.style.backgroundColor = benchmark.backgroundColor();
+ benchmark.run().then(function(testData) {
+ var suiteResults = self._suitesResults[suite.name] || {};
+ suiteResults[test.name] = testData;
+ self._suitesResults[suite.name] = suiteResults;
+
+ if (self._client && self._client.didRunTest)
+ self._client.didRunTest(testData);
+
+ state.next();
+ if (state.currentSuite() != suite)
+ self._removeFrame();
+ promise.resolve(state);
+ });
+
+ return promise;
+ },
+
+ step: function(state)
+ {
+ if (!state) {
+ state = new BenchmarkRunnerState(this._suites);
+ this._suitesResults = {};
+ }
+
+ var suite = state.currentSuite();
+ if (!suite) {
+ this._finalize();
+ var promise = new SimplePromise;
+ promise.resolve();
+ return promise;
+ }
+
+ if (state.isFirstTest()) {
+ this._appendFrame();
+ }
+
+ return state.prepareCurrentTest(this, this._frame).then(function(prepareReturnValue) {
+ return this._runBenchmarkAndRecordResults(state);
+ }.bind(this));
+ },
+
+ runAllSteps: function(startingState)
+ {
+ var nextCallee = this.runAllSteps.bind(this);
+ this.step(startingState).then(function(nextState) {
+ if (nextState)
+ nextCallee(nextState);
+ });
+ },
+
+ runMultipleIterations: function()
+ {
+ var self = this;
+ var currentIteration = 0;
+
+ this._runNextIteration = function() {
+ currentIteration++;
+ if (currentIteration < self._client.iterationCount)
+ self.runAllSteps();
+ else if (this._client && this._client.didFinishLastIteration) {
+ document.body.style.backgroundColor = "";
+ self._client.didFinishLastIteration();
+ }
+ }
+
+ if (this._client && this._client.willStartFirstIteration)
+ this._client.willStartFirstIteration();
+
+ this.runAllSteps();
+ },
+
+ _finalize: function()
+ {
+ this._removeFrame();
+
+ if (this._client && this._client.didRunSuites)
+ this._client.didRunSuites(this._suitesResults);
+
+ if (this._runNextIteration)
+ this._runNextIteration();
+ }
+});
diff --git a/third_party/webkit/PerformanceTests/MotionMark/resources/runner/crystal.svg b/third_party/webkit/PerformanceTests/MotionMark/resources/runner/crystal.svg
new file mode 100644
index 0000000000..0090df6c0c
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/resources/runner/crystal.svg
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright © 2016 Apple Inc. All rights reserved. -->
+<svg viewBox="0 0 1000 1000" preserveAspectRatio="none" version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <g fill="white" stroke="white" stroke-width="0.15">
+ <path fill-opacity="1" stroke-opacity="1" d=" M 0 0 L 327.88 0 C 325.14 2.87 322.60 5.94 319.73 8.68 C 315.84 12.50 311.31 16.05 309.30 21.31 C 303.10 37.43 296.87 53.54 290.57 69.62 C 288.47 75.11 285.91 80.43 284.24 86.07 C 285.81 87.43 287.37 88.81 289.07 90.01 C 311.23 105.31 332.96 121.25 355.21 136.43 C 357.15 140.82 359.76 145.01 360.61 149.80 C 361.24 153.54 361.64 157.34 361.37 161.13 C 358.55 166.08 356.04 171.21 353.27 176.19 C 353.07 176.54 352.67 177.23 352.48 177.57 C 350 179.82 347.14 181.57 344.29 183.30 C 335.73 188.47 327.27 193.80 318.71 198.98 C 308.13 198.76 297.56 199.12 287.01 199.74 C 279.65 200.20 272.27 199.53 264.92 200.02 C 262.30 200.09 259.91 201.30 257.93 202.94 C 238.82 218.89 219.07 234.08 199.86 249.90 C 196.40 252.94 194.22 257.05 191.56 260.74 C 185.35 267.44 176.30 270.51 169.90 276.91 C 167.71 282.16 169.92 288.14 170.35 293.60 C 171.49 300.35 172.29 307.14 173.21 313.92 C 173.56 316.94 174.94 319.79 177.25 321.80 C 191.06 333.94 203.32 347.74 217.23 359.78 C 225.25 367.81 233.44 375.66 241.21 383.92 C 240.08 390.20 237.63 396.53 238.91 402.98 C 243.04 426.95 247.04 450.94 251.10 474.92 C 252.01 480.25 253.09 485.59 253.21 491.02 C 252.78 493.08 252.36 495.16 251.80 497.20 C 245.46 503.93 239.30 510.88 232.53 517.18 C 229.17 519.86 225.15 522.50 223.72 526.76 C 222.48 536.86 222.68 547.08 221.69 557.21 C 221.55 562.43 220.62 567.83 222.17 572.93 C 227.92 589.76 231.93 607.12 236.76 624.23 C 237.77 628.08 239 631.89 239.78 635.81 C 236.34 648.91 232.70 661.96 229.12 675.02 C 221.78 676.32 214.41 674.68 207.03 674.87 C 197.35 675.08 187.73 673.63 178.06 673.91 C 167.70 674.16 157.40 672.47 147.04 672.92 C 134.73 673.25 122.45 671.07 110.15 672.14 C 114.51 679.54 119.71 686.40 124.41 693.59 C 143.51 722.45 162.87 751.15 181.98 780 C 185.26 784.93 191.47 785.96 196.30 788.75 C 197.35 794.78 196.74 800.90 196.84 806.98 C 196.94 817.65 196.93 828.31 196.97 838.98 C 197.12 846.82 196.23 854.78 198.23 862.46 C 198.18 870.99 198.91 879.57 197.90 888.06 C 196.92 891.68 197.94 895.32 199.28 898.70 C 195.30 904.88 190.33 910.34 185.64 915.99 C 178.89 920.62 171.57 924.35 164.65 928.72 C 158.28 932.76 151.41 936 145.28 940.39 C 140 944.77 136.22 950.60 131.64 955.65 C 128.24 959.88 124.34 963.73 121.19 968.16 C 119.32 970.80 120.37 974.22 120.59 977.20 C 121.77 984.78 122.70 992.40 123.77 1000 L 0 1000 L 0 0 Z"/>
+ <path fill-opacity="0.9883" stroke-opacity="0.9883" d=" M 169.90 276.91 C 176.30 270.51 185.35 267.44 191.56 260.74 C 195.63 265.49 201.89 267.02 207.24 269.80 C 229.32 280.67 251.38 291.56 273.44 302.46 C 289.29 309.67 304.43 318.39 320.48 325.16 C 323.79 331.38 327.72 337.24 331.27 343.31 C 301.44 357.25 271.05 370 241.21 383.92 C 233.44 375.66 225.25 367.81 217.23 359.78 C 203.32 347.74 191.06 333.94 177.25 321.80 C 174.94 319.79 173.56 316.94 173.21 313.92 C 172.29 307.14 171.49 300.35 170.35 293.60 C 169.92 288.14 167.71 282.16 169.90 276.91 Z"/>
+ <path fill-opacity="0.9804" stroke-opacity="0.9804" d=" M 110.15 672.14 C 122.45 671.07 134.73 673.25 147.04 672.92 C 157.40 672.47 167.70 674.16 178.06 673.91 C 187.73 673.63 197.35 675.08 207.03 674.87 C 214.41 674.68 221.78 676.32 229.12 675.02 C 230.32 677.25 231.56 679.45 232.90 681.60 C 233.20 683.35 233.22 685.15 232.89 686.92 C 226.83 717.17 221.18 747.50 215.10 777.75 C 209.29 781.47 203.40 785.09 197.76 789.07 C 197.63 813.54 198.62 838 198.23 862.46 C 196.23 854.78 197.12 846.82 196.97 838.98 C 196.93 828.31 196.94 817.65 196.84 806.98 C 196.74 800.90 197.35 794.78 196.30 788.75 C 191.47 785.96 185.26 784.93 181.98 780 C 162.87 751.15 143.51 722.45 124.41 693.59 C 119.71 686.40 114.51 679.54 110.15 672.14 Z"/>
+ <path fill-opacity="0.9687" stroke-opacity="0.9687" d=" M 287.01 199.74 C 297.56 199.12 308.13 198.76 318.71 198.98 C 320.17 228.28 318.86 257.66 320.23 286.97 C 320.34 299.70 320.40 312.43 320.48 325.16 C 304.43 318.39 289.29 309.67 273.44 302.46 C 251.38 291.56 229.32 280.67 207.24 269.80 C 201.89 267.02 195.63 265.49 191.56 260.74 C 194.22 257.05 196.40 252.94 199.86 249.90 C 219.07 234.08 238.82 218.89 257.93 202.94 C 259.91 201.30 262.30 200.09 264.92 200.02 C 272.27 199.53 279.65 200.20 287.01 199.74 Z"/>
+ <path fill-opacity="0.953" stroke-opacity="0.953" d=" M 327.88 0 L 373.98 0 C 367.79 45.48 361.61 90.97 355.21 136.43 C 332.96 121.25 311.23 105.31 289.07 90.01 C 287.37 88.81 285.81 87.43 284.24 86.07 C 285.91 80.43 288.47 75.11 290.57 69.62 C 296.87 53.54 303.10 37.43 309.30 21.31 C 311.31 16.05 315.84 12.50 319.73 8.68 C 322.60 5.94 325.14 2.87 327.88 0 Z"/>
+ <path fill-opacity="0.9491" stroke-opacity="0.9491" d=" M 164.65 928.72 C 171.57 924.35 178.89 920.62 185.64 915.99 C 186.75 944 188.72 971.99 190.07 1000 L 123.77 1000 C 122.70 992.40 121.77 984.78 120.59 977.20 C 120.37 974.22 119.32 970.80 121.19 968.16 C 124.34 963.73 128.24 959.88 131.64 955.65 C 136.22 950.60 140 944.77 145.28 940.39 C 151.41 936 158.28 932.76 164.65 928.72 Z"/>
+ <path fill-opacity="0.9295" stroke-opacity="0.9295" d=" M 331.27 343.31 C 342.73 349.21 354.49 354.50 365.86 360.56 C 366.36 361.84 366.86 363.12 367.37 364.41 C 367.21 366.77 366.28 368.98 365.20 371.06 C 362.81 375.78 360.53 380.54 358.35 385.36 C 345.47 397.11 333.54 409.87 321.09 422.06 C 299.90 443.25 278.73 464.47 257.50 485.61 C 255.90 487.27 254.44 489.06 253.21 491.02 C 253.09 485.59 252.01 480.25 251.10 474.92 C 247.04 450.94 243.04 426.95 238.91 402.98 C 237.63 396.53 240.08 390.20 241.21 383.92 C 271.05 370 301.44 357.25 331.27 343.31 Z"/>
+ <path fill-opacity="0.8785" stroke-opacity="0.8785" d=" M 223.72 526.76 C 225.15 522.50 229.17 519.86 232.53 517.18 C 238.93 523.27 246.16 528.39 253.01 533.95 C 280.84 556.11 308.83 578.09 336.63 600.29 C 341.10 603.79 346.07 606.93 349.22 611.79 C 350.70 615.38 352.13 618.98 353.74 622.52 C 347.24 625.52 339.96 624.93 333.04 625.88 C 301.97 629.40 270.82 632.13 239.78 635.81 C 239 631.89 237.77 628.08 236.76 624.23 C 231.93 607.12 227.92 589.76 222.17 572.93 C 220.62 567.83 221.55 562.43 221.69 557.21 C 222.68 547.08 222.48 536.86 223.72 526.76 Z"/>
+ <path fill-opacity="0.8746" stroke-opacity="0.8746" d=" M 199.28 898.70 C 203.46 901.06 207.86 902.98 212.33 904.76 C 214.88 905.73 217.17 907.37 218.69 909.68 C 225.30 927.02 231.55 944.50 238.11 961.86 C 239.21 964.87 240.62 967.82 241.15 971.02 C 241.25 973.62 240.44 976.14 239.87 978.66 C 238.03 985.74 236.68 992.94 234.74 1000 L 190.07 1000 C 188.72 971.99 186.75 944 185.64 915.99 C 190.33 910.34 195.30 904.88 199.28 898.70 Z"/>
+ <path fill-opacity="0.8706" stroke-opacity="0.8706" d=" M 232.90 681.60 C 235.14 683.02 237.58 684.12 240.11 684.93 C 258.41 690.06 276.85 694.79 294.93 700.68 C 304.80 726.80 314.30 753.06 323.99 779.25 C 321.69 780.75 319.57 782.51 317.43 784.23 C 283.33 781.96 249.22 779.81 215.10 777.75 C 221.18 747.50 226.83 717.17 232.89 686.92 C 233.22 685.15 233.20 683.35 232.90 681.60 Z"/>
+ <path fill-opacity="0.8589" stroke-opacity="0.8589" d=" M 353.74 622.52 C 354.67 624.51 355 626.71 354.72 628.90 C 354.14 631.20 353.60 633.50 353.05 635.80 C 350.68 639.43 347.58 642.48 344.71 645.70 C 328.13 664.04 311.35 682.20 294.93 700.68 C 276.85 694.79 258.41 690.06 240.11 684.93 C 237.58 684.12 235.14 683.02 232.90 681.60 C 231.56 679.45 230.32 677.25 229.12 675.02 C 232.70 661.96 236.34 648.91 239.78 635.81 C 270.82 632.13 301.97 629.40 333.04 625.88 C 339.96 624.93 347.24 625.52 353.74 622.52 Z"/>
+ <path fill-opacity="0.855" stroke-opacity="0.855" d=" M 197.76 789.07 C 203.40 785.09 209.29 781.47 215.10 777.75 C 249.22 779.81 283.33 781.96 317.43 784.23 C 315.73 791.84 313.84 799.40 312.11 807 C 310.31 810.16 307.51 812.57 304.47 814.49 C 287.18 825.78 270.27 837.63 253.03 848.98 C 236.55 859.79 220.52 871.26 203.96 881.93 C 201.52 883.50 199.47 885.61 197.90 888.06 C 198.91 879.57 198.18 870.99 198.23 862.46 C 198.62 838 197.63 813.54 197.76 789.07 Z"/>
+ <path fill-opacity="0.855" stroke-opacity="0.855" d=" M 344.29 183.30 C 347.14 181.57 350 179.82 352.48 177.57 C 352.77 181.76 355.26 185.30 357.10 188.94 C 365.30 204.47 373.30 220.10 381.52 235.62 C 383.12 238.45 384.06 241.61 384.44 244.84 C 387.81 271.89 391.59 298.89 394.85 325.96 C 385.10 337.41 375.36 348.89 365.86 360.56 C 354.49 354.50 342.73 349.21 331.27 343.31 C 327.72 337.24 323.79 331.38 320.48 325.16 C 320.40 312.43 320.34 299.70 320.23 286.97 C 318.86 257.66 320.17 228.28 318.71 198.98 C 327.27 193.80 335.73 188.47 344.29 183.30 Z"/>
+ <path fill-opacity="0.8432" stroke-opacity="0.8432" d=" M 321.09 422.06 C 333.54 409.87 345.47 397.11 358.35 385.36 C 358.79 393.90 358 402.41 357.61 410.93 C 357.58 424.29 356.35 437.61 356.32 450.97 C 355.30 462.60 355.77 474.29 354.82 485.93 C 354.49 491.91 354.57 497.91 354.23 503.90 C 350.84 504.27 347.41 504.51 344.01 504.17 C 313.30 501.45 282.48 500.24 251.80 497.20 C 252.36 495.16 252.78 493.08 253.21 491.02 C 254.44 489.06 255.90 487.27 257.50 485.61 C 278.73 464.47 299.90 443.25 321.09 422.06 Z"/>
+ <path fill-opacity="0.8393" stroke-opacity="0.8393" d=" M 373.98 0 L 375.50 0 C 397.90 16.47 420.67 32.46 443.14 48.85 C 449.83 53.79 456.77 58.38 463.25 63.61 C 431.93 89.13 400.82 114.91 369.61 140.56 C 366.28 143.28 362.37 145.67 360.61 149.80 C 359.76 145.01 357.15 140.82 355.21 136.43 C 361.61 90.97 367.79 45.48 373.98 0 Z"/>
+ <path fill-opacity="0.8275" stroke-opacity="0.8275" d=" M 251.80 497.20 C 282.48 500.24 313.30 501.45 344.01 504.17 C 347.41 504.51 350.84 504.27 354.23 503.90 C 357.03 506.62 361.90 508.29 361.97 512.80 C 358.05 541.20 353.99 569.58 349.99 597.97 C 349.44 602.54 347.90 607.21 349.22 611.79 C 346.07 606.93 341.10 603.79 336.63 600.29 C 308.83 578.09 280.84 556.11 253.01 533.95 C 246.16 528.39 238.93 523.27 232.53 517.18 C 239.30 510.88 245.46 503.93 251.80 497.20 Z"/>
+ <path fill-opacity="0.8197" stroke-opacity="0.8197" d=" M 304.47 814.49 C 307.51 812.57 310.31 810.16 312.11 807 C 310.99 813.29 311.73 819.70 311.72 826.05 C 312.47 837.02 312.51 848.02 312.50 859.01 C 300.69 875.28 289.35 891.88 277.41 908.05 C 270.37 909.81 263.17 908.36 256.04 908.19 C 249.68 907.96 243.30 908.12 236.94 907.87 C 231.21 907.71 225.49 906.94 219.75 907.36 C 219.49 907.94 218.96 909.10 218.69 909.68 C 217.17 907.37 214.88 905.73 212.33 904.76 C 207.86 902.98 203.46 901.06 199.28 898.70 C 197.94 895.32 196.92 891.68 197.90 888.06 C 199.47 885.61 201.52 883.50 203.96 881.93 C 220.52 871.26 236.55 859.79 253.03 848.98 C 270.27 837.63 287.18 825.78 304.47 814.49 Z"/>
+ <path fill-opacity="0.7844" stroke-opacity="0.7844" d=" M 219.75 907.36 C 225.49 906.94 231.21 907.71 236.94 907.87 C 243.30 908.12 249.68 907.96 256.04 908.19 C 263.17 908.36 270.37 909.81 277.41 908.05 C 279.98 912.58 284.54 915.31 288.41 918.60 C 295.15 924.19 301.91 929.75 308.65 935.35 C 313.06 939.14 318.10 942.31 321.57 947.09 C 318.07 952.97 314.74 958.95 311.43 964.94 C 302.10 970.37 292.91 976.03 283.57 981.44 C 281.17 982.96 278.31 984.13 276.66 986.54 C 275.16 990.86 275.11 995.50 274.48 1000 L 234.74 1000 C 236.68 992.94 238.03 985.74 239.87 978.66 C 240.44 976.14 241.25 973.62 241.15 971.02 C 240.62 967.82 239.21 964.87 238.11 961.86 C 231.55 944.50 225.30 927.02 218.69 909.68 C 218.96 909.10 219.49 907.94 219.75 907.36 Z"/>
+ <path fill-opacity="0.7687" stroke-opacity="0.7687" d=" M 375.50 0 L 548.99 0 C 548.07 11.56 546.25 23.02 544.95 34.54 C 525.98 45.47 506.58 55.63 487.69 66.69 C 479.58 65.38 471.41 64.56 463.25 63.61 C 456.77 58.38 449.83 53.79 443.14 48.85 C 420.67 32.46 397.90 16.47 375.50 0 Z"/>
+ <path fill-opacity="0.7569" stroke-opacity="0.7569" d=" M 352.48 177.57 C 352.67 177.23 353.07 176.54 353.27 176.19 C 355.78 178.93 358.62 181.38 361.89 183.17 C 373.79 190.05 384.67 198.48 396.38 205.65 C 405.55 211.85 415.12 217.43 424.07 223.95 C 435.96 231.69 447.97 239.23 459.67 247.26 C 464.57 250.45 469.33 253.97 474.82 256.12 C 481.80 259.13 489.74 260.31 495.64 265.43 C 491.08 270.99 486.53 276.57 481.84 282.02 C 453.09 297.13 423.63 310.91 394.85 325.96 C 391.59 298.89 387.81 271.89 384.44 244.84 C 384.06 241.61 383.12 238.45 381.52 235.62 C 373.30 220.10 365.30 204.47 357.10 188.94 C 355.26 185.30 352.77 181.76 352.48 177.57 Z"/>
+ <path fill-opacity="0.753" stroke-opacity="0.753" d=" M 369.61 140.56 C 400.82 114.91 431.93 89.13 463.25 63.61 C 471.41 64.56 479.58 65.38 487.69 66.69 C 486.82 82.73 485.05 98.72 483.75 114.73 C 483.15 119.05 483.64 123.99 480.54 127.48 C 469.52 141.36 458.63 155.35 447.54 169.17 C 426.29 167.96 405.18 164.93 383.98 162.95 C 376.44 162.39 368.97 160.61 361.37 161.13 C 361.64 157.34 361.24 153.54 360.61 149.80 C 362.37 145.67 366.28 143.28 369.61 140.56 Z"/>
+ <path fill-opacity="0.7491" stroke-opacity="0.7491" d=" M 344.71 645.70 C 347.58 642.48 350.68 639.43 353.05 635.80 C 353.70 641.86 356.06 647.52 357.70 653.34 C 367.82 686.89 378.38 720.31 388.25 753.93 C 381.61 761.08 375.26 768.49 368.57 775.58 C 353.73 777.09 338.83 777.79 323.99 779.25 C 314.30 753.06 304.80 726.80 294.93 700.68 C 311.35 682.20 328.13 664.04 344.71 645.70 Z"/>
+ <path fill-opacity="0.7491" stroke-opacity="0.7491" d=" M 367.37 364.41 C 368.87 366.30 370.70 367.89 372.63 369.33 C 379.75 374.55 386.90 379.73 394 384.98 C 396.46 386.66 397.68 389.46 398.65 392.18 C 409.39 422.55 420.71 452.72 431.53 483.07 C 430.70 484.02 429.91 485 429.06 485.94 C 421.71 492.88 414.29 499.73 407.01 506.74 C 393.67 507.87 380.29 508.51 366.96 509.77 C 364.79 509.76 362.96 510.89 361.97 512.80 C 361.90 508.29 357.03 506.62 354.23 503.90 C 354.57 497.91 354.49 491.91 354.82 485.93 C 355.77 474.29 355.30 462.60 356.32 450.97 C 356.35 437.61 357.58 424.29 357.61 410.93 C 358 402.41 358.79 393.90 358.35 385.36 C 360.53 380.54 362.81 375.78 365.20 371.06 C 366.28 368.98 367.21 366.77 367.37 364.41 Z"/>
+ <path fill-opacity="0.7451" stroke-opacity="0.7451" d=" M 361.37 161.13 C 368.97 160.61 376.44 162.39 383.98 162.95 C 405.18 164.93 426.29 167.96 447.54 169.17 C 456.58 182.09 466.70 194.20 476.10 206.86 C 488.03 222.59 500.24 238.11 512.07 253.92 C 506.49 257.58 500.73 261.09 495.64 265.43 C 489.74 260.31 481.80 259.13 474.82 256.12 C 469.33 253.97 464.57 250.45 459.67 247.26 C 447.97 239.23 435.96 231.69 424.07 223.95 C 415.12 217.43 405.55 211.85 396.38 205.65 C 384.67 198.48 373.79 190.05 361.89 183.17 C 358.62 181.38 355.78 178.93 353.27 176.19 C 356.04 171.21 358.55 166.08 361.37 161.13 Z"/>
+ <path fill-opacity="0.7334" stroke-opacity="0.7334" d=" M 283.57 981.44 C 292.91 976.03 302.10 970.37 311.43 964.94 C 311.57 976.62 311.48 988.31 311.52 1000 L 274.48 1000 C 275.11 995.50 275.16 990.86 276.66 986.54 C 278.31 984.13 281.17 982.96 283.57 981.44 Z"/>
+ <path fill-opacity="0.702" stroke-opacity="0.702" d=" M 366.96 509.77 C 380.29 508.51 393.67 507.87 407.01 506.74 C 415.89 532.41 425.55 557.83 433.99 583.64 C 427.09 595.62 420.28 607.64 413.32 619.59 C 395.24 621.90 377.04 623.19 358.94 625.21 C 356.73 625.22 355.69 627.25 354.72 628.90 C 355 626.71 354.67 624.51 353.74 622.52 C 352.13 618.98 350.70 615.38 349.22 611.79 C 347.90 607.21 349.44 602.54 349.99 597.97 C 353.99 569.58 358.05 541.20 361.97 512.80 C 362.96 510.89 364.79 509.76 366.96 509.77 Z"/>
+ <path fill-opacity="0.6942" stroke-opacity="0.6942" d=" M 312.50 859.01 C 318.79 860.71 324.36 864.19 330.34 866.66 C 340.54 871.48 351.13 875.47 361.11 880.75 C 368.34 888.78 374.93 897.37 382.12 905.45 C 382.47 918.41 383.24 931.35 383.76 944.30 C 383.10 944.93 382.45 945.58 381.81 946.23 C 365.22 945.99 348.63 946.36 332.05 946.01 C 328.52 945.92 325.03 946.45 321.57 947.09 C 318.10 942.31 313.06 939.14 308.65 935.35 C 301.91 929.75 295.15 924.19 288.41 918.60 C 284.54 915.31 279.98 912.58 277.41 908.05 C 289.35 891.88 300.69 875.28 312.50 859.01 Z"/>
+ <path fill-opacity="0.6746" stroke-opacity="0.6746" d=" M 323.99 779.25 C 338.83 777.79 353.73 777.09 368.57 775.58 C 370.03 778.30 371.42 781.07 373.10 783.67 C 370.01 804.70 367.76 825.84 365.06 846.93 C 363.76 858.20 362.03 869.43 361.11 880.75 C 351.13 875.47 340.54 871.48 330.34 866.66 C 324.36 864.19 318.79 860.71 312.50 859.01 C 312.51 848.02 312.47 837.02 311.72 826.05 C 311.73 819.70 310.99 813.29 312.11 807 C 313.84 799.40 315.73 791.84 317.43 784.23 C 319.57 782.51 321.69 780.75 323.99 779.25 Z"/>
+ <path fill-opacity="0.6589" stroke-opacity="0.6589" d=" M 321.57 947.09 C 325.03 946.45 328.52 945.92 332.05 946.01 C 348.63 946.36 365.22 945.99 381.81 946.23 C 381.69 964.15 381.80 982.08 381.76 1000 L 311.52 1000 C 311.48 988.31 311.57 976.62 311.43 964.94 C 314.74 958.95 318.07 952.97 321.57 947.09 Z"/>
+ <path fill-opacity="0.6314" stroke-opacity="0.6314" d=" M 358.94 625.21 C 377.04 623.19 395.24 621.90 413.32 619.59 C 425.37 632.53 438.16 644.78 450.52 657.44 C 451.82 658.56 451.93 660.27 451.97 661.90 C 447.59 684.96 442.57 707.90 437.80 730.89 C 437.35 732.71 436.78 734.49 436.25 736.30 C 420.39 742.54 404.13 747.73 388.25 753.93 C 378.38 720.31 367.82 686.89 357.70 653.34 C 356.06 647.52 353.70 641.86 353.05 635.80 C 353.60 633.50 354.14 631.20 354.72 628.90 C 355.69 627.25 356.73 625.22 358.94 625.21 Z"/>
+ <path fill-opacity="0.6314" stroke-opacity="0.6314" d=" M 394.85 325.96 C 423.63 310.91 453.09 297.13 481.84 282.02 C 482.68 291.99 484.20 301.89 485.40 311.82 C 488.58 336.52 491.67 361.24 494.97 385.93 C 495.24 388.17 495.36 390.43 495.27 392.70 C 494.98 393.29 494.40 394.47 494.11 395.06 C 462.25 392.21 430.37 389.52 398.47 387.18 C 398.50 388.85 398.54 390.51 398.65 392.18 C 397.68 389.46 396.46 386.66 394 384.98 C 386.90 379.73 379.75 374.55 372.63 369.33 C 370.70 367.89 368.87 366.30 367.37 364.41 C 366.86 363.12 366.36 361.84 365.86 360.56 C 375.36 348.89 385.10 337.41 394.85 325.96 Z"/>
+ <path fill-opacity="0.6314" stroke-opacity="0.6314" d=" M 480.54 127.48 C 483.64 123.99 483.15 119.05 483.75 114.73 C 483.90 118.96 482.75 124.41 486.59 127.38 C 511.90 148.19 537.31 168.90 562.41 189.96 C 550.38 210.51 538.52 231.18 526.52 251.76 C 521.72 252.59 516.86 253.04 512.07 253.92 C 500.24 238.11 488.03 222.59 476.10 206.86 C 466.70 194.20 456.58 182.09 447.54 169.17 C 458.63 155.35 469.52 141.36 480.54 127.48 Z"/>
+ <path fill-opacity="0.6197" stroke-opacity="0.6197" d=" M 373.10 783.67 C 390.18 802.89 407.31 822.08 424.17 841.49 C 410.02 862.72 396.01 884.05 382.12 905.45 C 374.93 897.37 368.34 888.78 361.11 880.75 C 362.03 869.43 363.76 858.20 365.06 846.93 C 367.76 825.84 370.01 804.70 373.10 783.67 Z"/>
+ <path fill-opacity="0.6157" stroke-opacity="0.6157" d=" M 398.47 387.18 C 430.37 389.52 462.25 392.21 494.11 395.06 C 507.28 424.63 520.52 454.18 533.57 483.80 C 528.28 485.95 522.52 485.07 516.98 485.08 C 504.66 484.88 492.32 485.08 480.02 484.26 C 467.69 483.86 455.35 484.30 443.02 483.80 C 438.32 483.76 433.07 482.84 429.06 485.94 C 429.91 485 430.70 484.02 431.53 483.07 C 420.71 452.72 409.39 422.55 398.65 392.18 C 398.54 390.51 398.50 388.85 398.47 387.18 Z"/>
+ <path fill-opacity="0.5844" stroke-opacity="0.5844" d=" M 429.06 485.94 C 433.07 482.84 438.32 483.76 443.02 483.80 C 455.35 484.30 467.69 483.86 480.02 484.26 C 492.32 485.08 504.66 484.88 516.98 485.08 C 522.52 485.07 528.28 485.95 533.57 483.80 C 539.79 490.34 548.27 494.09 555.36 499.59 C 547.53 515.61 539.53 531.54 531.63 547.53 C 524.45 551.24 516.61 553.33 509.10 556.22 C 484.10 565.46 458.83 573.99 433.99 583.64 C 425.55 557.83 415.89 532.41 407.01 506.74 C 414.29 499.73 421.71 492.88 429.06 485.94 Z"/>
+ <path fill-opacity="0.5844" stroke-opacity="0.5844" d=" M 487.69 66.69 C 506.58 55.63 525.98 45.47 544.95 34.54 C 550.76 41.24 556.83 47.69 562.76 54.28 C 565.32 56.80 565.60 60.52 566.26 63.85 C 573.05 98.77 580.17 133.62 586.97 168.53 C 578.90 175.81 570.40 182.60 562.41 189.96 C 537.31 168.90 511.90 148.19 486.59 127.38 C 482.75 124.41 483.90 118.96 483.75 114.73 C 485.05 98.72 486.82 82.73 487.69 66.69 Z"/>
+ <path fill-opacity="0.5216" stroke-opacity="0.5216" d=" M 512.07 253.92 C 516.86 253.04 521.72 252.59 526.52 251.76 C 537.09 261.81 548.06 271.42 558.82 281.26 C 560.14 282.51 561.34 283.91 562.33 285.44 C 569.52 301.98 576.13 318.78 583.48 335.24 C 569.63 344.96 555.01 353.54 540.85 362.81 C 530.10 369.71 519.35 376.60 508.59 383.48 C 504.06 386.41 499.26 389.01 495.27 392.70 C 495.36 390.43 495.24 388.17 494.97 385.93 C 491.67 361.24 488.58 336.52 485.40 311.82 C 484.20 301.89 482.68 291.99 481.84 282.02 C 486.53 276.57 491.08 270.99 495.64 265.43 C 500.73 261.09 506.49 257.58 512.07 253.92 Z"/>
+ <path fill-opacity="0.5138" stroke-opacity="0.5138" d=" M 436.25 736.30 C 436.78 734.49 437.35 732.71 437.80 730.89 C 437.78 732.79 437.53 734.80 438.22 736.64 C 441.14 739 444.70 740.31 448.01 742.02 C 462.68 749.32 477.27 756.77 491.94 764.07 C 498.79 767.56 505.82 770.74 512.43 774.71 C 501.34 792.40 490.14 810.02 479.01 827.69 C 463.85 832.35 448.92 837.79 433.68 842.17 C 430.49 842.09 427.33 841.75 424.17 841.49 C 407.31 822.08 390.18 802.89 373.10 783.67 C 371.42 781.07 370.03 778.30 368.57 775.58 C 375.26 768.49 381.61 761.08 388.25 753.93 C 404.13 747.73 420.39 742.54 436.25 736.30 Z"/>
+ <path fill-opacity="0.502" stroke-opacity="0.502" d=" M 424.17 841.49 C 427.33 841.75 430.49 842.09 433.68 842.17 C 443.79 868.94 454.79 895.37 465.16 922.04 C 460.56 929.15 456.37 936.52 451.83 943.68 C 429.14 944.14 406.45 944.27 383.76 944.30 C 383.24 931.35 382.47 918.41 382.12 905.45 C 396.01 884.05 410.02 862.72 424.17 841.49 Z"/>
+ <path fill-opacity="0.502" stroke-opacity="0.502" d=" M 509.10 556.22 C 516.61 553.33 524.45 551.24 531.63 547.53 C 531.09 554.71 532.47 561.85 532.51 569.03 C 533.82 590.96 534.99 612.90 536.37 634.83 C 536.49 638.03 536.17 641.23 535.71 644.41 C 511.02 648.82 486.33 653.26 461.60 657.44 C 458.13 658.12 453.60 658.08 451.97 661.90 C 451.93 660.27 451.82 658.56 450.52 657.44 C 438.16 644.78 425.37 632.53 413.32 619.59 C 420.28 607.64 427.09 595.62 433.99 583.64 C 458.83 573.99 484.10 565.46 509.10 556.22 Z"/>
+ <path fill-opacity="0.4589" stroke-opacity="0.4589" d=" M 383.76 944.30 C 406.45 944.27 429.14 944.14 451.83 943.68 C 458.08 952.20 465.10 960.12 471.58 968.46 C 473.14 970.27 472.78 972.79 472.87 975.02 C 472.77 983.34 472.82 991.67 472.82 1000 L 381.76 1000 C 381.80 982.08 381.69 964.15 381.81 946.23 C 382.45 945.58 383.10 944.93 383.76 944.30 Z"/>
+ <path fill-opacity="0.451" stroke-opacity="0.451" d=" M 536.37 634.83 C 536.58 638.08 536.48 641.43 537.46 644.58 C 539.62 647.76 543.06 649.85 545.15 653.11 C 545.66 658.17 544.69 663.26 544.85 668.34 C 544.21 689.37 543.11 710.37 542.39 731.40 C 534.92 744.44 528.94 758.25 522.46 771.80 C 519.13 772.81 515.79 773.78 512.43 774.71 C 505.82 770.74 498.79 767.56 491.94 764.07 C 477.27 756.77 462.68 749.32 448.01 742.02 C 444.70 740.31 441.14 739 438.22 736.64 C 437.53 734.80 437.78 732.79 437.80 730.89 C 442.57 707.90 447.59 684.96 451.97 661.90 C 453.60 658.08 458.13 658.12 461.60 657.44 C 486.33 653.26 511.02 648.82 535.71 644.41 C 536.17 641.23 536.49 638.03 536.37 634.83 Z"/>
+ <path fill-opacity="0.4471" stroke-opacity="0.4471" d=" M 583.48 335.24 C 584.46 336.34 585.53 337.35 586.52 338.44 C 588.74 340.41 587.58 343.67 587.71 346.25 C 584.34 395.33 580.99 444.42 577.57 493.49 C 574.88 494.46 572.34 495.77 569.64 496.68 C 564.91 497.79 560.10 498.51 555.36 499.59 C 548.27 494.09 539.79 490.34 533.57 483.80 C 520.52 454.18 507.28 424.63 494.11 395.06 C 494.40 394.47 494.98 393.29 495.27 392.70 C 499.26 389.01 504.06 386.41 508.59 383.48 C 519.35 376.60 530.10 369.71 540.85 362.81 C 555.01 353.54 569.63 344.96 583.48 335.24 Z"/>
+ <path fill-opacity="0.4393" stroke-opacity="0.4393" d=" M 433.68 842.17 C 448.92 837.79 463.85 832.35 479.01 827.69 C 488.83 848.96 499.05 870.04 508.51 891.47 C 493.97 901.52 479.45 911.63 465.16 922.04 C 454.79 895.37 443.79 868.94 433.68 842.17 Z"/>
+ <path fill-opacity="0.3961" stroke-opacity="0.3961" d=" M 548.99 0 L 752.49 0 C 751.57 1.16 751.04 2.54 750.61 3.94 C 750.16 5.19 749.66 6.42 749.13 7.64 C 719.08 25.92 689.52 45.01 659.60 63.50 C 656.73 65.18 653.97 67.02 651.37 69.08 C 655.42 91.72 659.79 114.31 664 136.92 C 664.77 141.83 666.66 146.76 665.62 151.78 C 651.11 157.78 637.30 165.39 622.97 171.81 C 610.97 170.72 598.96 169.67 586.97 168.53 C 580.17 133.62 573.05 98.77 566.26 63.85 C 565.60 60.52 565.32 56.80 562.76 54.28 C 556.83 47.69 550.76 41.24 544.95 34.54 C 546.25 23.02 548.07 11.56 548.99 0 Z"/>
+ <path fill-opacity="0.3687" stroke-opacity="0.3687" d=" M 586.97 168.53 C 598.96 169.67 610.97 170.72 622.97 171.81 C 633.32 193.14 643.74 214.44 653.61 235.98 C 648.65 244.69 642.86 252.90 637.62 261.44 C 617.19 268.02 596.43 273.61 575.89 279.86 C 571.29 281.46 565.79 281.59 562.33 285.44 C 561.34 283.91 560.14 282.51 558.82 281.26 C 548.06 271.42 537.09 261.81 526.52 251.76 C 538.52 231.18 550.38 210.51 562.41 189.96 C 570.40 182.60 578.90 175.81 586.97 168.53 Z"/>
+ <path fill-opacity="0.3412" stroke-opacity="0.3412" d=" M 512.43 774.71 C 515.79 773.78 519.13 772.81 522.46 771.80 C 527.25 776.63 532.88 780.51 538.16 784.78 C 551.94 795.69 565.68 806.65 579.53 817.48 C 583.79 820.92 588.31 824.07 592.20 827.94 C 592.18 829.33 592.15 830.72 592.12 832.13 C 590.98 839.36 589.97 846.61 588.75 853.84 C 575.55 867.75 562.90 882.18 549.54 895.94 C 535.74 896.31 522.21 892.68 508.51 891.47 C 499.05 870.04 488.83 848.96 479.01 827.69 C 490.14 810.02 501.34 792.40 512.43 774.71 Z"/>
+ <path fill-opacity="0.3334" stroke-opacity="0.3334" d=" M 508.51 891.47 C 522.21 892.68 535.74 896.31 549.54 895.94 C 550.96 909.71 554.66 923.17 556.88 936.84 C 557.08 938.56 557.22 940.29 557.38 942.04 C 547.38 951.07 536.31 958.85 526.01 967.53 C 508.78 968.54 491.54 969.34 474.31 970.32 C 473.64 980.19 474.22 990.10 474 1000 L 472.82 1000 C 472.82 991.67 472.77 983.34 472.87 975.02 C 472.78 972.79 473.14 970.27 471.58 968.46 C 465.10 960.12 458.08 952.20 451.83 943.68 C 456.37 936.52 460.56 929.15 465.16 922.04 C 479.45 911.63 493.97 901.52 508.51 891.47 Z"/>
+ <path fill-opacity="0.3216" stroke-opacity="0.3216" d=" M 575.89 279.86 C 596.43 273.61 617.19 268.02 637.62 261.44 C 649.11 279.16 662.99 295.22 674.57 312.89 C 669.49 320.50 664.96 328.47 659.86 336.06 C 653.09 339.62 646.32 343.23 639.31 346.27 C 631.42 347.71 623.67 344.91 615.87 344.16 C 607.08 343.27 598.47 341.13 589.67 340.37 C 588.99 342.32 588.24 344.25 587.71 346.25 C 587.58 343.67 588.74 340.41 586.52 338.44 C 585.53 337.35 584.46 336.34 583.48 335.24 C 576.13 318.78 569.52 301.98 562.33 285.44 C 565.79 281.59 571.29 281.46 575.89 279.86 Z"/>
+ <path fill-opacity="0.3138" stroke-opacity="0.3138" d=" M 589.67 340.37 C 598.47 341.13 607.08 343.27 615.87 344.16 C 623.67 344.91 631.42 347.71 639.31 346.27 C 639.01 352.18 641.28 357.74 642.65 363.39 C 651.70 398.56 660.94 433.68 670.10 468.83 C 671.32 473.15 672.40 477.53 673.10 481.98 C 671.85 483.92 670.76 485.95 669.63 487.95 C 638.97 490.28 608.24 491.42 577.57 493.49 C 580.99 444.42 584.34 395.33 587.71 346.25 C 588.24 344.25 588.99 342.32 589.67 340.37 Z"/>
+ <path fill-opacity="0.3059" stroke-opacity="0.3059" d=" M 474.31 970.32 C 491.54 969.34 508.78 968.54 526.01 967.53 C 528.79 978.42 531.84 989.24 535.09 1000 L 474 1000 C 474.22 990.10 473.64 980.19 474.31 970.32 Z"/>
+ <path fill-opacity="0.302" stroke-opacity="0.302" d=" M 555.36 499.59 C 560.10 498.51 564.91 497.79 569.64 496.68 C 591.15 547.16 611.72 598.03 633.23 648.51 C 632.96 649.01 632.42 650.02 632.14 650.52 C 628.14 651.22 624.08 651.24 620.05 651.15 C 608.68 650.98 597.35 652.06 585.99 652.11 C 572.75 652 559.51 652.48 546.31 653.29 C 546.11 658.33 545.82 663.38 544.85 668.34 C 544.69 663.26 545.66 658.17 545.15 653.11 C 543.06 649.85 539.62 647.76 537.46 644.58 C 536.48 641.43 536.58 638.08 536.37 634.83 C 534.99 612.90 533.82 590.96 532.51 569.03 C 532.47 561.85 531.09 554.71 531.63 547.53 C 539.53 531.54 547.53 515.61 555.36 499.59 Z"/>
+ <path fill-opacity="0.2902" stroke-opacity="0.2902" d=" M 659.60 63.50 C 689.52 45.01 719.08 25.92 749.13 7.64 C 746.17 14.12 744.09 20.95 741.61 27.61 C 726.43 69.59 711.39 111.61 696.08 153.54 C 685.90 153.39 675.80 150.55 665.62 151.78 C 666.66 146.76 664.77 141.83 664 136.92 C 659.79 114.31 655.42 91.72 651.37 69.08 C 653.97 67.02 656.73 65.18 659.60 63.50 Z"/>
+ <path fill-opacity="0.2746" stroke-opacity="0.2746" d=" M 665.62 151.78 C 675.80 150.55 685.90 153.39 696.08 153.54 C 702.53 158.23 709.03 162.85 715.68 167.28 C 717.91 168.86 720.74 170.41 720.95 173.49 C 716.99 189.35 712.80 205.17 708.55 220.96 C 702.71 227.74 695.30 233.01 689.72 240.03 C 694.43 258.79 700.76 277.13 705.65 295.85 C 695.53 301.97 684.56 306.57 674.57 312.89 C 662.99 295.22 649.11 279.16 637.62 261.44 C 642.86 252.90 648.65 244.69 653.61 235.98 C 643.74 214.44 633.32 193.14 622.97 171.81 C 637.30 165.39 651.11 157.78 665.62 151.78 Z"/>
+ <path fill-opacity="0.2667" stroke-opacity="0.2667" d=" M 633.23 648.51 C 636.96 652.72 642.83 653.38 647.86 655.15 C 655.21 657.70 662.83 659.66 669.81 663.16 L 670.43 664.19 C 665.52 670.04 659.35 674.61 653.88 679.89 C 637.25 694.84 621.03 710.27 604.11 724.89 C 602.47 726.05 600.74 727.07 598.95 727.97 C 580.06 728.51 561.27 730.89 542.39 731.40 C 543.11 710.37 544.21 689.37 544.85 668.34 C 545.82 663.38 546.11 658.33 546.31 653.29 C 559.51 652.48 572.75 652 585.99 652.11 C 597.35 652.06 608.68 650.98 620.05 651.15 C 624.08 651.24 628.14 651.22 632.14 650.52 C 632.42 650.02 632.96 649.01 633.23 648.51 Z"/>
+ <path fill-opacity="0.2471" stroke-opacity="0.2471" d=" M 542.39 731.40 C 561.27 730.89 580.06 728.51 598.95 727.97 C 602.54 748.12 605.51 768.37 609.47 788.45 C 611.30 797.84 612.25 807.43 615.07 816.61 C 608.49 819.78 601.98 823.09 595.50 826.47 C 593.13 827.36 592.63 829.94 592.12 832.13 C 592.15 830.72 592.18 829.33 592.20 827.94 C 588.31 824.07 583.79 820.92 579.53 817.48 C 565.68 806.65 551.94 795.69 538.16 784.78 C 532.88 780.51 527.25 776.63 522.46 771.80 C 528.94 758.25 534.92 744.44 542.39 731.40 Z"/>
+ <path fill-opacity="0.2471" stroke-opacity="0.2471" d=" M 556.88 936.84 C 557.66 939.47 558.49 942.39 560.93 944 C 571.58 951.44 582.47 958.56 593.27 965.78 C 596.97 967.84 596.04 972.66 596.15 976.20 C 595.57 984.13 594.99 992.06 594.47 1000 L 535.09 1000 C 531.84 989.24 528.79 978.42 526.01 967.53 C 536.31 958.85 547.38 951.07 557.38 942.04 C 557.22 940.29 557.08 938.56 556.88 936.84 Z"/>
+ <path fill-opacity="0.2393" stroke-opacity="0.2393" d=" M 577.57 493.49 C 608.24 491.42 638.97 490.28 669.63 487.95 C 672.64 492.67 676.16 497.03 679.42 501.58 C 681.82 504.89 682.08 509.10 682.98 512.96 C 686.01 527.26 689.06 541.56 692.18 555.85 C 694.79 566.71 694.12 577.96 695.28 589 C 695.40 597.90 696.86 606.75 696.49 615.66 C 687.62 631.50 678.62 647.28 669.81 663.16 C 662.83 659.66 655.21 657.70 647.86 655.15 C 642.83 653.38 636.96 652.72 633.23 648.51 C 611.72 598.03 591.15 547.16 569.64 496.68 C 572.34 495.77 574.88 494.46 577.57 493.49 Z"/>
+ <path fill-opacity="0.2236" stroke-opacity="0.2236" d=" M 598.95 727.97 C 600.74 727.07 602.47 726.05 604.11 724.89 C 605.28 730.81 609.93 734.93 613.55 739.44 C 619.31 746.36 624.56 753.68 630.34 760.59 C 639.19 771.33 647.40 782.57 656.31 793.26 C 651.21 797.42 646.65 802.22 641.58 806.42 C 632.98 810.38 623.89 813.17 615.07 816.61 C 612.25 807.43 611.30 797.84 609.47 788.45 C 605.51 768.37 602.54 748.12 598.95 727.97 Z"/>
+ <path fill-opacity="0.2236" stroke-opacity="0.2236" d=" M 639.31 346.27 C 646.32 343.23 653.09 339.62 659.86 336.06 C 686.51 356.31 713.55 376.05 740.33 396.14 C 737.83 405.13 735.79 414.24 733.43 423.26 C 726.43 430.99 718.38 437.67 711.03 445.06 C 698.51 457.49 685.27 469.21 673.10 481.98 C 672.40 477.53 671.32 473.15 670.10 468.83 C 660.94 433.68 651.70 398.56 642.65 363.39 C 641.28 357.74 639.01 352.18 639.31 346.27 Z"/>
+ <path fill-opacity="0.204" stroke-opacity="0.204" d=" M 670.43 664.19 C 673.37 669.51 676.64 674.69 680.28 679.57 C 680.07 685.74 678.68 691.78 677.73 697.87 C 672.88 727.26 667.93 756.63 663.09 786.02 C 663.02 789.97 658.96 791.26 656.31 793.26 C 647.40 782.57 639.19 771.33 630.34 760.59 C 624.56 753.68 619.31 746.36 613.55 739.44 C 609.93 734.93 605.28 730.81 604.11 724.89 C 621.03 710.27 637.25 694.84 653.88 679.89 C 659.35 674.61 665.52 670.04 670.43 664.19 Z"/>
+ <path fill-opacity="0.204" stroke-opacity="0.204" d=" M 749.13 7.64 C 749.66 6.42 750.16 5.19 750.61 3.94 C 750.67 6.58 751.26 9.18 752.36 11.59 C 755.89 19.76 759.32 27.98 762.75 36.20 C 764.72 42.32 765.62 48.72 766.93 55.01 C 773.01 86.59 779.53 118.10 785.40 149.72 C 778.91 155.99 772.99 162.83 766.44 169.04 L 765.86 169.66 C 753.56 169.96 741.28 171.12 728.96 170.89 C 726.04 170.77 722.99 171.20 720.95 173.49 C 720.74 170.41 717.91 168.86 715.68 167.28 C 709.03 162.85 702.53 158.23 696.08 153.54 C 711.39 111.61 726.43 69.59 741.61 27.61 C 744.09 20.95 746.17 14.12 749.13 7.64 Z"/>
+ <path fill-opacity="0.1961" stroke-opacity="0.1961" d=" M 549.54 895.94 C 562.90 882.18 575.55 867.75 588.75 853.84 C 611.64 877.83 634.46 901.89 657.15 926.06 C 656.36 929.33 655.59 932.60 654.83 935.87 C 654.19 938.27 652.78 940.46 650.40 941.42 C 633.66 949.65 616.96 957.96 600.28 966.30 C 596.10 967.73 596.74 972.66 596.15 976.20 C 596.04 972.66 596.97 967.84 593.27 965.78 C 582.47 958.56 571.58 951.44 560.93 944 C 558.49 942.39 557.66 939.47 556.88 936.84 C 554.66 923.17 550.96 909.71 549.54 895.94 Z"/>
+ <path fill-opacity="0.1922" stroke-opacity="0.1922" d=" M 689.72 240.03 C 695.30 233.01 702.71 227.74 708.55 220.96 C 729.63 237.23 751.13 252.97 772.39 269.02 C 774.53 273.76 776.69 278.50 778.34 283.45 C 772.10 290.31 765.48 296.90 759.75 304.18 C 758.77 315.38 760.52 326.70 760.51 337.95 C 760.45 347.13 761.52 356.26 761.54 365.43 C 761.72 367.63 760.46 369.50 759.20 371.16 C 752.89 379.47 746.40 387.65 740.33 396.14 C 713.55 376.05 686.51 356.31 659.86 336.06 C 664.96 328.47 669.49 320.50 674.57 312.89 C 684.56 306.57 695.53 301.97 705.65 295.85 C 700.76 277.13 694.43 258.79 689.72 240.03 Z"/>
+ <path fill-opacity="0.1726" stroke-opacity="0.1726" d=" M 728.96 170.89 C 741.28 171.12 753.56 169.96 765.86 169.66 C 767.88 202.79 770.11 235.91 772.39 269.02 C 751.13 252.97 729.63 237.23 708.55 220.96 C 712.80 205.17 716.99 189.35 720.95 173.49 C 722.99 171.20 726.04 170.77 728.96 170.89 Z"/>
+ <path fill-opacity="0.1373" stroke-opacity="0.1373" d=" M 615.07 816.61 C 623.89 813.17 632.98 810.38 641.58 806.42 C 645.25 814.64 651.10 821.57 655.80 829.20 C 662.57 839.43 669.51 849.54 676.01 859.95 C 683.53 871.53 691.70 882.72 698.41 894.81 C 684.54 905.07 670.88 915.62 657.15 926.06 C 634.46 901.89 611.64 877.83 588.75 853.84 C 589.97 846.61 590.98 839.36 592.12 832.13 C 592.63 829.94 593.13 827.36 595.50 826.47 C 601.98 823.09 608.49 819.78 615.07 816.61 Z"/>
+ <path fill-opacity="0.1295" stroke-opacity="0.1295" d=" M 650.40 941.42 C 652.78 940.46 654.19 938.27 654.83 935.87 C 654.11 940.20 656.63 943.95 659.34 947.04 C 659.81 955.51 657.31 963.73 656.19 972.06 C 654.57 981.35 653.10 990.68 651.63 1000 L 594.47 1000 C 594.99 992.06 595.57 984.13 596.15 976.20 C 596.74 972.66 596.10 967.73 600.28 966.30 C 616.96 957.96 633.66 949.65 650.40 941.42 Z"/>
+ <path fill-opacity="0.1099" stroke-opacity="0.1099" d=" M 762.75 36.20 C 766.71 41.26 771.97 45.04 776.93 49.06 C 798.92 67.11 821.26 84.72 843.22 102.80 C 851.79 109.79 860.76 116.35 868.75 124.02 C 863.32 131.42 858.08 138.97 852.75 146.45 C 840.17 147.38 827.57 148.12 814.96 148.25 C 805.13 149.30 795.23 148.69 785.40 149.72 C 779.53 118.10 773.01 86.59 766.93 55.01 C 765.62 48.72 764.72 42.32 762.75 36.20 Z"/>
+ <path fill-opacity="0.1099" stroke-opacity="0.1099" d=" M 765.86 169.66 L 766.44 169.04 C 772.86 175.47 779.26 181.93 786.19 187.83 C 793.68 195.35 801.97 202.02 809.24 209.77 C 815.06 215.97 821.92 221.08 827.75 227.28 C 832.77 232.60 838.67 236.99 843.78 242.23 C 851.02 249.65 858.99 256.30 866.37 263.58 C 867.88 265.06 868.96 266.92 869.91 268.80 C 847.35 272.31 824.78 275.77 802.23 279.32 C 794.26 280.71 786.20 281.51 778.34 283.45 C 776.69 278.50 774.53 273.76 772.39 269.02 C 770.11 235.91 767.88 202.79 765.86 169.66 Z"/>
+ <path fill-opacity="0.0981" stroke-opacity="0.0981" d=" M 659.34 947.04 C 666.64 954.72 675.44 960.72 683.61 967.40 C 686.99 969.43 686.98 973.49 686.86 976.98 C 686.69 984.65 686.91 992.33 686.56 1000 L 651.63 1000 C 653.10 990.68 654.57 981.35 656.19 972.06 C 657.31 963.73 659.81 955.51 659.34 947.04 Z"/>
+ <path fill-opacity="0.0981" stroke-opacity="0.0981" d=" M 680.28 679.57 C 687.62 684.43 696.11 687.13 703.96 691.05 C 722.31 699.32 740.63 707.71 759 715.95 C 762.03 718.58 764.89 721.40 767.81 724.15 C 770.49 726.35 772.43 729.42 771.89 733.04 C 769.33 746.88 766.91 760.75 764.61 774.64 C 764.05 778.01 763.04 781.33 761.34 784.31 C 757.72 790.74 754.18 797.21 750.52 803.62 C 749.47 805.68 747.92 807.89 748.63 810.32 C 750.24 817.07 752.40 823.68 754.30 830.36 C 749.73 838.49 743.41 845.43 738.03 853.02 C 728.16 866.13 718.43 879.35 708.50 892.42 C 705.14 893.21 701.73 893.85 698.41 894.81 C 691.70 882.72 683.53 871.53 676.01 859.95 C 669.51 849.54 662.57 839.43 655.80 829.20 C 651.10 821.57 645.25 814.64 641.58 806.42 C 646.65 802.22 651.21 797.42 656.31 793.26 C 658.96 791.26 663.02 789.97 663.09 786.02 C 667.93 756.63 672.88 727.26 677.73 697.87 C 678.68 691.78 680.07 685.74 680.28 679.57 Z"/>
+ <path fill-opacity="0.0942" stroke-opacity="0.0942" d=" M 752.49 0 L 873.98 0 C 876.68 6.74 879 13.64 881.62 20.41 C 884.17 26.93 884.36 34.01 885.38 40.86 C 888.28 61.72 890.87 82.62 893.89 103.47 C 886.04 110.94 876.82 116.79 868.75 124.02 C 860.76 116.35 851.79 109.79 843.22 102.80 C 821.26 84.72 798.92 67.11 776.93 49.06 C 771.97 45.04 766.71 41.26 762.75 36.20 C 759.32 27.98 755.89 19.76 752.36 11.59 C 751.26 9.18 750.67 6.58 750.61 3.94 C 751.04 2.54 751.57 1.16 752.49 0 Z"/>
+ <path fill-opacity="0.0902" stroke-opacity="0.0902" d=" M 814.96 148.25 C 827.57 148.12 840.17 147.38 852.75 146.45 C 858.94 167.78 866.25 188.79 873.07 209.93 C 878.63 227.75 884.77 245.39 890.20 263.25 C 889.15 265.06 888.17 266.92 887.29 268.81 C 881.49 268.88 875.70 268.56 869.91 268.80 C 868.96 266.92 867.88 265.06 866.37 263.58 C 858.99 256.30 851.02 249.65 843.78 242.23 C 838.67 236.99 832.77 232.60 827.75 227.28 C 821.92 221.08 815.06 215.97 809.24 209.77 C 801.97 202.02 793.68 195.35 786.19 187.83 C 779.26 181.93 772.86 175.47 766.44 169.04 C 772.99 162.83 778.91 155.99 785.40 149.72 C 795.23 148.69 805.13 149.30 814.96 148.25 Z"/>
+ <path fill-opacity="0.0863" stroke-opacity="0.0863" d=" M 711.03 445.06 C 718.38 437.67 726.43 430.99 733.43 423.26 C 738.41 425.93 743.61 428.13 748.88 430.14 C 768.70 438.32 788.46 446.63 808.31 454.74 C 812.63 456.62 817.39 457.76 821.21 460.63 C 822.11 462.68 822.15 464.98 822.32 467.19 C 820.49 484.05 818.56 500.89 816.77 517.75 C 817 524.38 810.75 528.04 808.89 533.89 C 806.01 541.30 802.91 548.62 799.98 556.01 C 797.54 562.18 794.18 568.14 793.58 574.87 C 792.35 587.55 790.89 600.21 789.56 612.88 C 788.95 614.74 788.18 616.55 787.51 618.40 C 777.69 617.60 767.85 616.72 757.99 616.99 C 745.96 617.26 733.99 615.75 721.96 615.93 C 713.46 616.06 704.97 614.27 696.49 615.66 C 696.86 606.75 695.40 597.90 695.28 589 C 694.12 577.96 694.79 566.71 692.18 555.85 C 689.06 541.56 686.01 527.26 682.98 512.96 C 682.08 509.10 681.82 504.89 679.42 501.58 C 676.16 497.03 672.64 492.67 669.63 487.95 C 670.76 485.95 671.85 483.92 673.10 481.98 C 685.27 469.21 698.51 457.49 711.03 445.06 Z"/>
+ <path fill-opacity="0.0746" stroke-opacity="0.0746" d=" M 696.49 615.66 C 704.97 614.27 713.46 616.06 721.96 615.93 C 733.99 615.75 745.96 617.26 757.99 616.99 C 767.85 616.72 777.69 617.60 787.51 618.40 C 777.55 650.78 768.67 683.48 759 715.95 C 740.63 707.71 722.31 699.32 703.96 691.05 C 696.11 687.13 687.62 684.43 680.28 679.57 C 676.64 674.69 673.37 669.51 670.43 664.19 L 669.81 663.16 C 678.62 647.28 687.62 631.50 696.49 615.66 Z"/>
+ <path fill-opacity="0.0746" stroke-opacity="0.0746" d=" M 869.91 268.80 C 875.70 268.56 881.49 268.88 887.29 268.81 C 886.50 273.37 886.89 278.07 885.72 282.57 C 876.65 314.58 867.66 346.61 858.72 378.65 C 857.40 387.68 864.96 395.07 865.78 403.83 C 865.33 406.05 864.08 407.99 863.01 409.95 C 856.26 421.20 850.06 432.78 843.28 444.01 C 837.58 449.10 831.44 453.68 825.64 458.64 C 822.98 460.65 822.73 464.15 822.32 467.19 C 822.15 464.98 822.11 462.68 821.21 460.63 C 817.39 457.76 812.63 456.62 808.31 454.74 C 788.46 446.63 768.70 438.32 748.88 430.14 C 743.61 428.13 738.41 425.93 733.43 423.26 C 735.79 414.24 737.83 405.13 740.33 396.14 C 746.40 387.65 752.89 379.47 759.20 371.16 C 760.46 369.50 761.72 367.63 761.54 365.43 C 761.52 356.26 760.45 347.13 760.51 337.95 C 760.52 326.70 758.77 315.38 759.75 304.18 C 765.48 296.90 772.10 290.31 778.34 283.45 C 786.20 281.51 794.26 280.71 802.23 279.32 C 824.78 275.77 847.35 272.31 869.91 268.80 Z"/>
+ <path fill-opacity="0.0667" stroke-opacity="0.0667" d=" M 698.41 894.81 C 701.73 893.85 705.14 893.21 708.50 892.42 C 713.85 898.11 719.92 903.07 725.25 908.79 C 732.04 916.01 739.89 922.12 746.75 929.26 C 752.61 935.29 758.94 940.86 764.30 947.36 C 758.51 952.88 752.97 958.67 746.93 963.92 C 743.30 967.28 739.36 970.38 736.29 974.28 C 734.56 976.45 734.77 979.39 734.68 982.01 C 734.75 988 734.87 994 734.71 1000 L 686.56 1000 C 686.91 992.33 686.69 984.65 686.86 976.98 C 686.98 973.49 686.99 969.43 683.61 967.40 C 675.44 960.72 666.64 954.72 659.34 947.04 C 656.63 943.95 654.11 940.20 654.83 935.87 C 655.59 932.60 656.36 929.33 657.15 926.06 C 670.88 915.62 684.54 905.07 698.41 894.81 Z"/>
+ <path fill-opacity="0.0471" stroke-opacity="0.0471" d=" M 787.51 618.40 C 788.18 616.55 788.95 614.74 789.56 612.88 C 789.88 614.38 790.15 615.94 790.82 617.36 C 794.07 619.90 798.13 621.09 801.67 623.19 C 805.40 628.31 808.55 633.82 811.83 639.23 C 817.87 649.15 824.12 658.93 830.19 668.84 C 833.45 674.34 837.55 679.47 839.28 685.74 C 836.01 694.64 832.64 703.52 829.63 712.52 C 825.16 716.10 819.26 716.46 813.95 717.96 C 801.60 721.33 789.17 724.40 776.82 727.73 C 774 728.09 772.74 730.65 771.89 733.04 C 772.43 729.42 770.49 726.35 767.81 724.15 C 764.89 721.40 762.03 718.58 759 715.95 C 768.67 683.48 777.55 650.78 787.51 618.40 Z"/>
+ <path fill-opacity="0.0432" stroke-opacity="0.0432" d=" M 754.30 830.36 C 760.41 835.62 767.69 839.19 774.38 843.62 C 793.35 855.31 812.26 867.09 831.20 878.84 C 834.71 881.16 839.88 882.84 840.16 887.80 C 835.77 902.44 832.15 917.30 828.05 932.03 C 826.65 937.67 821.99 941.47 818.08 945.42 C 808.76 946.55 799.37 945.61 790.03 946.14 C 781.47 946.93 772.87 946.89 764.30 947.36 C 758.94 940.86 752.61 935.29 746.75 929.26 C 739.89 922.12 732.04 916.01 725.25 908.79 C 719.92 903.07 713.85 898.11 708.50 892.42 C 718.43 879.35 728.16 866.13 738.03 853.02 C 743.41 845.43 749.73 838.49 754.30 830.36 Z"/>
+ <path fill-opacity="0.0353" stroke-opacity="0.0353" d=" M 808.89 533.89 C 810.75 528.04 817 524.38 816.77 517.75 C 816.73 520.32 817.11 522.87 817.56 525.40 C 832.54 532.40 848.09 538.17 863.22 544.85 C 865.98 545.63 865.90 548.79 866.30 551.10 C 862.94 566.99 860.24 583 856.85 598.88 C 856.09 601.52 854.54 604.04 851.66 604.67 C 838.22 609.05 824.97 613.99 811.60 618.56 C 808.12 619.72 804.84 621.37 801.67 623.19 C 798.13 621.09 794.07 619.90 790.82 617.36 C 790.15 615.94 789.88 614.38 789.56 612.88 C 790.89 600.21 792.35 587.55 793.58 574.87 C 794.18 568.14 797.54 562.18 799.98 556.01 C 802.91 548.62 806.01 541.30 808.89 533.89 Z"/>
+ <path fill-opacity="0.0314" stroke-opacity="0.0314" d=" M 893.89 103.47 C 906.72 109.97 920.98 112.62 934.39 117.61 C 947.25 122.33 960.45 126.10 973.36 130.67 C 974.09 136.90 973.52 143.23 974.75 149.42 C 975.16 156.15 978.35 164.36 973.07 169.95 C 950.88 194.15 929.29 218.90 907.14 243.13 C 901.51 249.85 894.98 255.86 890.20 263.25 C 884.77 245.39 878.63 227.75 873.07 209.93 C 866.25 188.79 858.94 167.78 852.75 146.45 C 858.08 138.97 863.32 131.42 868.75 124.02 C 876.82 116.79 886.04 110.94 893.89 103.47 Z"/>
+ <path fill-opacity="0.0275" stroke-opacity="0.0275" d=" M 790.03 946.14 C 799.37 945.61 808.76 946.55 818.08 945.42 C 817.60 963.61 818.21 981.81 817.75 1000 L 734.71 1000 C 734.87 994 734.75 988 734.68 982.01 C 734.77 979.39 734.56 976.45 736.29 974.28 C 739.36 970.38 743.30 967.28 746.93 963.92 C 752.97 958.67 758.51 952.88 764.30 947.36 C 772.87 946.89 781.47 946.93 790.03 946.14 Z"/>
+ <path fill-opacity="0.0236" stroke-opacity="0.0236" d=" M 873.98 0 L 1000 0 L 1000 103.37 C 993.93 110.15 987.92 117.01 981.22 123.19 C 978.82 125.72 975.31 128.07 975.22 131.91 C 975.04 137.75 975.28 143.60 974.75 149.42 C 973.52 143.23 974.09 136.90 973.36 130.67 C 960.45 126.10 947.25 122.33 934.39 117.61 C 920.98 112.62 906.72 109.97 893.89 103.47 C 890.87 82.62 888.28 61.72 885.38 40.86 C 884.36 34.01 884.17 26.93 881.62 20.41 C 879 13.64 876.68 6.74 873.98 0 Z"/>
+ <path fill-opacity="0.0197" stroke-opacity="0.0197" d=" M 813.95 717.96 C 819.26 716.46 825.16 716.10 829.63 712.52 C 832.23 717.98 837.20 721.57 841.62 725.46 C 855.50 738.57 869.89 751.14 883.88 764.14 C 887.48 767.46 892.20 770.22 893.70 775.19 C 895.08 779.49 895.87 783.95 896.79 788.37 C 897.04 790.36 897.79 792.67 896.47 794.46 C 894.23 797.83 891.15 800.52 888.69 803.72 C 885.29 807.93 883.06 812.88 880.64 817.67 C 871.47 834.90 862.59 852.27 853.59 869.60 C 851.55 873.40 849.91 877.61 846.52 880.46 C 844.06 882.58 841.54 884.78 840.16 887.80 C 839.88 882.84 834.71 881.16 831.20 878.84 C 812.26 867.09 793.35 855.31 774.38 843.62 C 767.69 839.19 760.41 835.62 754.30 830.36 C 752.40 823.68 750.24 817.07 748.63 810.32 C 747.92 807.89 749.47 805.68 750.52 803.62 C 754.18 797.21 757.72 790.74 761.34 784.31 C 763.04 781.33 764.05 778.01 764.61 774.64 C 766.91 760.75 769.33 746.88 771.89 733.04 C 772.74 730.65 774 728.09 776.82 727.73 C 789.17 724.40 801.60 721.33 813.95 717.96 Z"/>
+ <path fill-opacity="0.0197" stroke-opacity="0.0197" d=" M 825.64 458.64 C 831.44 453.68 837.58 449.10 843.28 444.01 C 848.20 449.37 853.71 454.12 859.06 459.03 C 878.31 476.08 896.94 493.83 916.28 510.78 C 920.39 514.58 920.49 520.85 919.86 526.02 C 918.54 530.85 915.41 536.24 910.06 537.19 C 896.89 539.99 883.68 542.68 870.57 545.70 C 867.74 546 866.93 548.78 866.30 551.10 C 865.90 548.79 865.98 545.63 863.22 544.85 C 848.09 538.17 832.54 532.40 817.56 525.40 C 817.11 522.87 816.73 520.32 816.77 517.75 C 818.56 500.89 820.49 484.05 822.32 467.19 C 822.73 464.15 822.98 460.65 825.64 458.64 Z"/>
+ <path fill-opacity="0.0157" stroke-opacity="0.0157" d=" M 851.66 604.67 C 854.54 604.04 856.09 601.52 856.85 598.88 C 856.82 602.45 857.75 606.09 860.32 608.70 C 865.38 614.29 870.41 619.92 875.17 625.79 C 881.34 633.49 888.28 640.56 894.26 648.42 C 892.01 651.58 888.48 653.35 885.26 655.34 C 874.38 662.07 863.58 668.92 852.86 675.89 C 848.21 678.98 842.80 681.24 839.28 685.74 C 837.55 679.47 833.45 674.34 830.19 668.84 C 824.12 658.93 817.87 649.15 811.83 639.23 C 808.55 633.82 805.40 628.31 801.67 623.19 C 804.84 621.37 808.12 619.72 811.60 618.56 C 824.97 613.99 838.22 609.05 851.66 604.67 Z"/>
+ </g>
+</svg>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/resources/runner/lines.svg b/third_party/webkit/PerformanceTests/MotionMark/resources/runner/lines.svg
new file mode 100644
index 0000000000..83458b8095
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/resources/runner/lines.svg
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright © 2016 Apple Inc. All rights reserved. -->
+<svg viewBox="0 0 1052 1251" version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <g fill-opacity="0.5" fill="white">
+ <polygon points="221.761719 0 223.761719 0 2.12833345 1250.36328 0.128333454 1250.36328"/>
+ <polygon points="261.761719 0 265.761719 0 44.1283335 1250.36328 40.1283335 1250.36328"/>
+ <polygon points="301.761719 0 307.761719 0 86.1283335 1250.36328 80.1283335 1250.36328"/>
+ <polygon points="341.761719 0 349.761719 0 128.128333 1250.36328 120.128333 1250.36328"/>
+ <polygon points="381.761719 0 391.761719 0 170.128333 1250.36328 160.128333 1250.36328"/>
+ <polygon points="421.761719 0 433.761719 0 212.128333 1250.36328 200.128333 1250.36328"/>
+ <polygon points="461.761719 0 475.761719 0 254.128333 1250.36328 240.128333 1250.36328"/>
+ <polygon points="501.761719 0 517.761719 0 296.128333 1250.36328 280.128333 1250.36328"/>
+ <polygon points="541.761719 0 559.761719 0 338.128333 1250.36328 320.128333 1250.36328"/>
+ <polygon points="581.761719 0 601.761719 0 380.128333 1250.36328 360.128333 1250.36328"/>
+ <polygon points="621.761719 0 643.761719 0 422.128333 1250.36328 400.128333 1250.36328"/>
+ <polygon points="661.761719 0 685.761719 0 464.128333 1250.36328 440.128333 1250.36328"/>
+ <polygon points="701.761719 0 727.761719 0 506.128333 1250.36328 480.128333 1250.36328"/>
+ <polygon points="741.761719 0 769.761719 0 548.128333 1250.36328 520.128333 1250.36328"/>
+ <polygon points="781.761719 0 811.761719 0 590.128333 1250.36328 560.128333 1250.36328"/>
+ <polygon points="821.761719 0 853.761719 0 632.128333 1250.36328 600.128333 1250.36328"/>
+ <polygon points="861.761719 0 895.761719 0 674.128333 1250.36328 640.128333 1250.36328"/>
+ <polygon points="901.761719 0 937.761719 0 716.128333 1250.36328 680.128333 1250.36328"/>
+ <polygon points="941.761719 0 979.76172 0 758.128333 1250.36328 720.128333 1250.36328"/>
+ <polygon points="981.76172 0 1021.76172 0 800.128333 1250.36328 760.128333 1250.36328"/>
+ </g>
+</svg>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/resources/runner/logo.svg b/third_party/webkit/PerformanceTests/MotionMark/resources/runner/logo.svg
new file mode 100644
index 0000000000..a7d0eaf375
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/resources/runner/logo.svg
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright © 2016 Apple Inc. All rights reserved. -->
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <symbol id="root" viewBox="0 0 6882 1698">
+ <path d="M 1314 1681 L 1466 1681 L 1549 1282 C 1555 1254 1566 1229 1582 1205 C 1598 1181 1614 1162 1629 1147 C 1644 1132 1662 1119 1683 1108 C 1704 1097 1729 1092 1758 1092 C 1790 1092 1812 1100 1824 1117 C 1836 1134 1842 1154 1842 1177 C 1842 1197 1840 1219 1835 1241 C 1830 1263 1826 1283 1822 1301 L 1743 1680 L 1895 1680 L 1979 1277 C 1983 1257 1989 1237 2000 1215 C 2010 1193 2024 1173 2040 1155 C 2056 1137 2076 1122 2099 1110 C 2122 1098 2148 1092 2177 1092 C 2197 1092 2213 1095 2225 1101 C 2237 1107 2247 1114 2254 1124 C 2261 1133 2266 1144 2268 1156 C 2270 1168 2271 1180 2271 1191 C 2270 1208 2268 1224 2265 1238 C 2262 1253 2259 1264 2258 1272 L 2173 1680 L 2325 1680 L 2413 1240 C 2416 1228 2418 1213 2420 1197 C 2422 1181 2423 1167 2423 1154 C 2423 1098 2407 1054 2375 1021 C 2343 988 2294 972 2227 972 C 2179 972 2136 984 2098 1007 C 2060 1030 2025 1059 1994 1095 C 1984 1050 1963 1018 1931 1000 C 1899 982 1862 973 1819 973 C 1771 973 1727 983 1686 1004 C 1646 1025 1611 1054 1583 1091 L 1580 1088 L 1600 991 L 1456 991 L 1313 1680 L 1314 1681 Z" fill-opacity="0.6" fill="black"/>
+ <path d="M 2673 1426 C 2690 1410 2711 1399 2736 1391 C 2760 1383 2787 1379 2815 1377 C 2843 1375 2868 1373 2889 1372 C 2906 1370 2923 1367 2941 1363 C 2959 1359 2973 1351 2984 1340 L 2987 1343 C 2982 1376 2974 1407 2965 1436 C 2956 1465 2943 1490 2926 1511 C 2910 1532 2889 1549 2863 1562 C 2838 1574 2806 1581 2769 1581 C 2755 1581 2741 1579 2726 1576 C 2712 1573 2699 1568 2687 1561 C 2675 1554 2666 1545 2658 1534 C 2650 1523 2647 1509 2647 1492 C 2647 1464 2656 1442 2673 1426 L 2673 1426 Z M 3155 1237 L 3155 1237 C 3164 1198 3168 1163 3168 1133 C 3168 1121 3166 1105 3163 1087 C 3159 1069 3149 1051 3133 1034 C 3117 1017 3091 1003 3056 991 C 3021 979 2972 973 2910 973 C 2869 973 2831 977 2795 984 C 2759 992 2727 1004 2698 1023 C 2670 1041 2646 1065 2626 1094 C 2606 1123 2593 1159 2585 1201 L 2729 1201 C 2740 1158 2760 1130 2791 1115 C 2822 1100 2858 1093 2901 1093 C 2932 1093 2959 1099 2982 1110 C 3005 1121 3017 1143 3017 1176 C 3017 1202 3011 1223 2998 1239 C 2985 1255 2965 1265 2937 1266 C 2887 1270 2837 1274 2785 1278 C 2747 1281 2710 1286 2676 1295 C 2641 1304 2611 1318 2584 1336 C 2557 1355 2536 1378 2520 1407 C 2504 1436 2496 1472 2496 1514 C 2496 1544 2502 1571 2513 1594 C 2525 1617 2540 1636 2560 1651 C 2580 1666 2603 1678 2629 1686 C 2655 1694 2682 1698 2710 1698 C 2753 1698 2794 1691 2835 1677 C 2876 1663 2911 1641 2942 1610 C 2944 1637 2953 1658 2970 1674 C 2987 1690 3008 1698 3034 1698 C 3054 1698 3074 1696 3094 1692 C 3114 1688 3133 1684 3153 1679 L 3177 1570 C 3168 1571 3159 1572 3150 1575 C 3141 1577 3132 1578 3123 1578 C 3111 1578 3102 1575 3098 1570 C 3094 1565 3091 1557 3091 1547 C 3091 1537 3093 1527 3096 1515 L 3105 1479 L 3156 1235 L 3155 1237 Z" fill-opacity="0.6" fill="black"/>
+ <path d="M 3232 1681 L 3384 1681 L 3448 1376 C 3455 1341 3465 1308 3477 1277 C 3489 1246 3506 1218 3526 1194 C 3546 1170 3570 1151 3599 1137 C 3628 1123 3662 1116 3701 1116 C 3710 1116 3719 1116 3728 1117 C 3737 1118 3746 1119 3755 1121 L 3787 976 C 3775 974 3762 973 3750 973 C 3738 973 3726 972 3713 972 C 3689 972 3666 977 3644 986 C 3622 995 3602 1007 3583 1022 C 3564 1037 3547 1053 3532 1072 C 3516 1091 3503 1109 3493 1128 L 3490 1125 L 3518 990 L 3374 990 L 3231 1679 L 3232 1681 Z" fill-opacity="0.6" fill="black"/>
+
+ <polygon fill-opacity="0.6" fill="black" points="3726 1681 3878 1681 3927 1446 4044 1346 4166 1681 4334 1681 4166 1245 4470 992 4278 992 3966 1270 3963 1268 4075 729 3923 729"/>
+ <polygon fill-opacity="0.1" fill="black" points="4915 1368 4961 1118 1429 1118 1457 986 6867 986"/>
+
+ <polygon fill="black" points="4930 1298 4976 1048 1444 1048 1472 916 6882 916"/>
+
+ <polygon fill="currentColor" points="1403 263 1257 263 965 1679 1118 1679"/>
+ <polygon fill-opacity="0.8" fill="currentColor" points="1007 263 930 263 639 1679 722 1679"/>
+ <polygon fill-opacity="0.6" fill="currentColor" points="653 263 618 263 326 1679 368 1679"/>
+ <polygon fill-opacity="0.4" fill="currentColor" points="305 263 291 263 0 1679 21 1679"/>
+
+ <path d="M 1466 952 L 1618 952 L 1701 553 C 1707 525 1718 500 1734 476 C 1750 452 1766 433 1781 418 C 1796 403 1814 390 1835 379 C 1856 368 1881 363 1910 363 C 1942 363 1964 371 1976 388 C 1988 405 1994 425 1994 448 C 1994 468 1992 490 1987 512 C 1982 534 1978 554 1974 572 L 1895 951 L 2047 951 L 2131 548 C 2135 528 2141 508 2152 486 C 2162 464 2176 444 2192 426 C 2208 408 2228 393 2251 381 C 2274 369 2300 363 2329 363 C 2349 363 2365 366 2377 372 C 2389 378 2399 385 2406 395 C 2413 404 2418 415 2420 427 C 2422 439 2423 451 2423 462 C 2422 479 2420 495 2417 509 C 2414 524 2411 535 2410 543 L 2325 951 L 2477 951 L 2565 511 C 2568 499 2570 484 2572 468 C 2574 452 2575 438 2575 425 C 2575 369 2559 325 2527 292 C 2495 259 2446 243 2379 243 C 2331 243 2288 255 2250 278 C 2212 301 2177 330 2146 366 C 2136 321 2115 289 2083 271 C 2051 253 2014 244 1971 244 C 1923 244 1879 254 1838 275 C 1798 296 1763 325 1735 362 L 1732 359 L 1752 262 L 1608 262 L 1465 951 L 1466 952 Z" fill="black"/>
+ <path d="M 3180 415 C 3205 449 3218 491 3218 542 C 3218 577 3213 612 3204 649 C 3195 686 3180 719 3161 749 C 3141 779 3117 803 3088 822 C 3059 841 3025 851 2986 851 C 2931 851 2891 834 2865 800 C 2840 766 2827 724 2827 673 C 2827 638 2832 603 2841 566 C 2850 530 2865 496 2884 467 C 2904 437 2928 413 2957 393 C 2986 373 3020 364 3059 364 C 3114 364 3154 381 3180 415 L 3180 415 Z M 3141 938 L 3141 938 C 3189 916 3231 885 3265 847 C 3299 808 3325 763 3343 710 C 3361 658 3370 601 3370 541 C 3370 444 3344 371 3291 320 C 3239 270 3164 245 3068 245 C 3008 245 2954 257 2906 280 C 2858 303 2816 334 2782 373 C 2748 412 2721 457 2703 508 C 2684 559 2675 613 2675 670 C 2675 767 2701 841 2754 893 C 2806 945 2881 971 2977 971 C 3038 971 3093 960 3142 938 L 3141 938 Z" fill="black"/>
+ <path d="M 3620 263 L 3500 263 L 3476 376 L 3596 376 L 3517 753 C 3515 759 3513 770 3511 786 C 3509 802 3508 817 3508 830 C 3508 846 3510 862 3514 877 C 3518 893 3525 906 3535 918 C 3545 930 3559 940 3577 947 C 3595 954 3617 958 3645 958 C 3665 958 3685 957 3708 954 C 3730 951 3751 948 3771 943 L 3796 831 C 3781 835 3766 837 3753 837 C 3739 837 3727 838 3715 838 C 3692 838 3677 833 3670 824 C 3663 815 3660 802 3660 787 C 3660 779 3661 768 3664 755 C 3667 742 3670 727 3673 712 L 3744 375 L 3881 375 L 3905 262 L 3768 262 L 3811 55 L 3663 55 L 3620 262 L 3620 263 Z" fill="black"/>
+ <path d="M 4046 144 L 4197 144 L 4226 0 L 4075 0 L 4046 144 L 4046 144 Z M 3878 952 L 3878 952 L 4030 952 L 4173 263 L 4021 263 L 3878 952 L 3878 952 Z" fill="black"/>
+ <path d="M 4736 415 C 4761 449 4774 491 4774 542 C 4774 577 4769 612 4760 649 C 4751 686 4736 719 4717 749 C 4697 779 4673 803 4644 822 C 4615 841 4581 851 4542 851 C 4487 851 4447 834 4421 800 C 4396 766 4383 724 4383 673 C 4383 638 4388 603 4397 566 C 4406 530 4421 496 4440 467 C 4460 437 4484 413 4513 393 C 4542 373 4576 364 4615 364 C 4670 364 4710 381 4736 415 L 4736 415 Z M 4697 938 L 4697 938 C 4745 916 4787 885 4821 847 C 4855 808 4881 763 4899 710 C 4917 658 4926 601 4926 541 C 4926 444 4900 371 4847 320 C 4795 270 4720 245 4624 245 C 4564 245 4510 257 4462 280 C 4414 303 4372 334 4338 373 C 4304 412 4277 457 4259 508 C 4240 559 4231 613 4231 670 C 4231 767 4257 841 4310 893 C 4362 945 4437 971 4533 971 C 4594 971 4649 960 4698 938 L 4697 938 Z" fill="black"/>
+ <path d="M 4990 952 L 5142 952 L 5219 579 C 5225 551 5235 523 5248 497 C 5261 471 5276 449 5294 431 C 5313 412 5334 397 5357 384 C 5381 371 5407 365 5438 365 C 5466 365 5487 369 5501 377 C 5516 385 5526 395 5532 406 C 5538 417 5542 428 5542 439 C 5542 450 5543 458 5543 464 C 5543 474 5542 484 5540 495 C 5538 506 5535 517 5533 528 L 5445 953 L 5597 953 L 5689 513 C 5692 501 5693 486 5694 470 C 5695 454 5695 440 5695 427 C 5695 371 5679 327 5646 294 C 5614 261 5563 245 5493 245 C 5445 245 5400 256 5359 277 C 5318 298 5283 328 5256 366 L 5253 363 L 5274 263 L 5131 263 L 4988 952 L 4990 952 Z" fill="black"/>
+ </symbol>
+</svg>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/resources/runner/tests.js b/third_party/webkit/PerformanceTests/MotionMark/resources/runner/tests.js
new file mode 100644
index 0000000000..aa938c5189
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/resources/runner/tests.js
@@ -0,0 +1,81 @@
+var Headers = {
+ testName: [
+ {
+ title: "<span onclick='benchmarkController.showDebugInfo()'>" + Strings.text.testName + "</span>",
+ text: Strings.text.testName
+ }
+ ],
+ score: [
+ {
+ title: Strings.text.score,
+ text: Strings.json.score
+ }
+ ],
+ details: [
+ {
+ title: "&nbsp;",
+ text: function(data) {
+ var bootstrap = data[Strings.json.complexity][Strings.json.bootstrap];
+ return "<span>±" + (Statistics.largestDeviationPercentage(bootstrap.confidenceLow, bootstrap.median, bootstrap.confidenceHigh) * 100).toFixed(2) + "%</span>";
+ }
+ }
+ ]
+};
+
+var Suite = function(name, tests) {
+ this.name = name;
+ this.tests = tests;
+};
+
+var Suites = [];
+
+Suites.push(new Suite("Animometer",
+ [
+ {
+ url: "master/multiply.html",
+ name: "Multiply"
+ },
+ {
+ url: "master/canvas-stage.html?pathType=arcs",
+ name: "Canvas Arcs"
+ },
+ {
+ url: "master/leaves.html",
+ name: "Leaves"
+ },
+ {
+ url: "master/canvas-stage.html?pathType=linePath",
+ name: "Paths"
+ },
+ {
+ url: "master/canvas-stage.html?pathType=line&lineCap=square",
+ name: "Canvas Lines"
+ },
+ {
+ url: "master/focus.html",
+ name: "Focus"
+ },
+ {
+ url: "master/image-data.html",
+ name: "Images"
+ },
+ {
+ url: "master/text.html",
+ name: "Design"
+ },
+ {
+ url: "master/svg-particles.html",
+ name: "Suits"
+ },
+ ]
+));
+
+function suiteFromName(name)
+{
+ return Suites.find(function(suite) { return suite.name == name; });
+}
+
+function testFromName(suite, name)
+{
+ return suite.tests.find(function(test) { return test.name == name; });
+}
diff --git a/third_party/webkit/PerformanceTests/MotionMark/resources/statistics.js b/third_party/webkit/PerformanceTests/MotionMark/resources/statistics.js
new file mode 100644
index 0000000000..9322a797b6
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/resources/statistics.js
@@ -0,0 +1,397 @@
+Pseudo =
+{
+ initialRandomSeed: 49734321,
+ randomSeed: 49734321,
+
+ resetRandomSeed: function()
+ {
+ Pseudo.randomSeed = Pseudo.initialRandomSeed;
+ },
+
+ random: function()
+ {
+ var randomSeed = Pseudo.randomSeed;
+ randomSeed = ((randomSeed + 0x7ed55d16) + (randomSeed << 12)) & 0xffffffff;
+ randomSeed = ((randomSeed ^ 0xc761c23c) ^ (randomSeed >>> 19)) & 0xffffffff;
+ randomSeed = ((randomSeed + 0x165667b1) + (randomSeed << 5)) & 0xffffffff;
+ randomSeed = ((randomSeed + 0xd3a2646c) ^ (randomSeed << 9)) & 0xffffffff;
+ randomSeed = ((randomSeed + 0xfd7046c5) + (randomSeed << 3)) & 0xffffffff;
+ randomSeed = ((randomSeed ^ 0xb55a4f09) ^ (randomSeed >>> 16)) & 0xffffffff;
+ Pseudo.randomSeed = randomSeed;
+ return (randomSeed & 0xfffffff) / 0x10000000;
+ }
+};
+
+Statistics =
+{
+ sampleMean: function(numberOfSamples, sum)
+ {
+ if (numberOfSamples < 1)
+ return 0;
+ return sum / numberOfSamples;
+ },
+
+ // With sum and sum of squares, we can compute the sample standard deviation in O(1).
+ // See https://rniwa.com/2012-11-10/sample-standard-deviation-in-terms-of-sum-and-square-sum-of-samples/
+ unbiasedSampleStandardDeviation: function(numberOfSamples, sum, squareSum)
+ {
+ if (numberOfSamples < 2)
+ return 0;
+ return Math.sqrt((squareSum - sum * sum / numberOfSamples) / (numberOfSamples - 1));
+ },
+
+ geometricMean: function(values)
+ {
+ if (!values.length)
+ return 0;
+ var roots = values.map(function(value) { return Math.pow(value, 1 / values.length); })
+ return roots.reduce(function(a, b) { return a * b; });
+ },
+
+ // Cumulative distribution function
+ cdf: function(value, mean, standardDeviation)
+ {
+ return 0.5 * (1 + Statistics.erf((value - mean) / (Math.sqrt(2 * standardDeviation * standardDeviation))));
+ },
+
+ // Approximation of Gauss error function, Abramowitz and Stegun 7.1.26
+ erf: function(value)
+ {
+ var sign = (value >= 0) ? 1 : -1;
+ value = Math.abs(value);
+
+ var a1 = 0.254829592;
+ var a2 = -0.284496736;
+ var a3 = 1.421413741;
+ var a4 = -1.453152027;
+ var a5 = 1.061405429;
+ var p = 0.3275911;
+
+ var t = 1.0 / (1.0 + p * value);
+ var y = 1.0 - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * Math.exp(-value * value);
+ return sign * y;
+ },
+
+ largestDeviationPercentage: function(low, mean, high)
+ {
+ return Math.max(Math.abs(low / mean - 1), (high / mean - 1));
+ }
+};
+
+Experiment = Utilities.createClass(
+ function(includeConcern)
+ {
+ if (includeConcern)
+ this._maxHeap = Heap.createMaxHeap(Experiment.defaults.CONCERN_SIZE);
+ this.reset();
+ }, {
+
+ reset: function()
+ {
+ this._sum = 0;
+ this._squareSum = 0;
+ this._numberOfSamples = 0;
+ if (this._maxHeap)
+ this._maxHeap.init();
+ },
+
+ get sampleCount()
+ {
+ return this._numberOfSamples;
+ },
+
+ sample: function(value)
+ {
+ this._sum += value;
+ this._squareSum += value * value;
+ if (this._maxHeap)
+ this._maxHeap.push(value);
+ ++this._numberOfSamples;
+ },
+
+ mean: function()
+ {
+ return Statistics.sampleMean(this._numberOfSamples, this._sum);
+ },
+
+ standardDeviation: function()
+ {
+ return Statistics.unbiasedSampleStandardDeviation(this._numberOfSamples, this._sum, this._squareSum);
+ },
+
+ cdf: function(value)
+ {
+ return Statistics.cdf(value, this.mean(), this.standardDeviation());
+ },
+
+ percentage: function()
+ {
+ var mean = this.mean();
+ return mean ? this.standardDeviation() * 100 / mean : 0;
+ },
+
+ concern: function(percentage)
+ {
+ if (!this._maxHeap)
+ return this.mean();
+
+ var size = Math.ceil(this._numberOfSamples * percentage / 100);
+ var values = this._maxHeap.values(size);
+ return values.length ? values.reduce(function(a, b) { return a + b; }) / values.length : 0;
+ },
+
+ score: function(percentage)
+ {
+ return Statistics.geometricMean([this.mean(), Math.max(this.concern(percentage), 1)]);
+ }
+});
+
+Experiment.defaults =
+{
+ CONCERN: 5,
+ CONCERN_SIZE: 100,
+};
+
+Regression = Utilities.createClass(
+ function(samples, getComplexity, getFrameLength, startIndex, endIndex, options)
+ {
+ var desiredFrameLength = options.desiredFrameLength || 1000/60;
+ var bestProfile;
+
+ if (!options.preferredProfile || options.preferredProfile == Strings.json.profiles.slope) {
+ var slope = this._calculateRegression(samples, getComplexity, getFrameLength, startIndex, endIndex, {
+ shouldClip: true,
+ s1: desiredFrameLength,
+ t1: 0
+ });
+ if (!bestProfile || slope.error < bestProfile.error) {
+ bestProfile = slope;
+ this.profile = Strings.json.profiles.slope;
+ }
+ }
+ if (!options.preferredProfile || options.preferredProfile == Strings.json.profiles.flat) {
+ var flat = this._calculateRegression(samples, getComplexity, getFrameLength, startIndex, endIndex, {
+ shouldClip: true,
+ s1: desiredFrameLength,
+ t1: 0,
+ t2: 0
+ });
+
+ if (!bestProfile || flat.error < bestProfile.error) {
+ bestProfile = flat;
+ this.profile = Strings.json.profiles.flat;
+ }
+ }
+
+ this.startIndex = Math.min(startIndex, endIndex);
+ this.endIndex = Math.max(startIndex, endIndex);
+
+ this.complexity = bestProfile.complexity;
+ this.s1 = bestProfile.s1;
+ this.t1 = bestProfile.t1;
+ this.s2 = bestProfile.s2;
+ this.t2 = bestProfile.t2;
+ this.stdev1 = bestProfile.stdev1;
+ this.stdev2 = bestProfile.stdev2;
+ this.n1 = bestProfile.n1;
+ this.n2 = bestProfile.n2;
+ this.error = bestProfile.error;
+ }, {
+
+ valueAt: function(complexity)
+ {
+ if (this.n1 == 1 || complexity > this.complexity)
+ return this.s2 + this.t2 * complexity;
+ return this.s1 + this.t1 * complexity;
+ },
+
+ // A generic two-segment piecewise regression calculator. Based on Kundu/Ubhaya
+ //
+ // Minimize sum of (y - y')^2
+ // where y = s1 + t1*x
+ // y = s2 + t2*x
+ // y' = s1 + t1*x' = s2 + t2*x' if x_0 <= x' <= x_n
+ //
+ // Allows for fixing s1, t1, s2, t2
+ //
+ // x is assumed to be complexity, y is frame length. Can be used for pure complexity-FPS
+ // analysis or for ramp controllers since complexity monotonically decreases with time.
+ _calculateRegression: function(samples, getComplexity, getFrameLength, startIndex, endIndex, options)
+ {
+ if (startIndex == endIndex) {
+ // Only one sample point; we can't calculate any regression.
+ var x = getComplexity(samples, startIndex);
+ return {
+ complexity: x,
+ s1: x,
+ t1: 0,
+ s2: x,
+ t2: 0,
+ error1: 0,
+ error2: 0
+ };
+ }
+
+ // x is expected to increase in complexity
+ var iterationDirection = endIndex > startIndex ? 1 : -1;
+ var lowComplexity = getComplexity(samples, startIndex);
+ var highComplexity = getComplexity(samples, endIndex);
+ var a1 = 0, b1 = 0, c1 = 0, d1 = 0, h1 = 0, k1 = 0;
+ var a2 = 0, b2 = 0, c2 = 0, d2 = 0, h2 = 0, k2 = 0;
+
+ // Iterate from low to high complexity
+ for (var i = startIndex; iterationDirection * (endIndex - i) > -1; i += iterationDirection) {
+ var x = getComplexity(samples, i);
+ var y = getFrameLength(samples, i);
+ a2 += 1;
+ b2 += x;
+ c2 += x * x;
+ d2 += y;
+ h2 += y * x;
+ k2 += y * y;
+ }
+
+ var s1_best, t1_best, s2_best, t2_best, n1_best, n2_best, error1_best, error2_best, x_best, x_prime;
+
+ function setBest(s1, t1, error1, s2, t2, error2, splitIndex, x_prime, x)
+ {
+ s1_best = s1;
+ t1_best = t1;
+ error1_best = error1;
+ s2_best = s2;
+ t2_best = t2;
+ error2_best = error2;
+ // Number of samples included in the first segment, inclusive of splitIndex
+ n1_best = iterationDirection * (splitIndex - startIndex) + 1;
+ // Number of samples included in the second segment
+ n2_best = iterationDirection * (endIndex - splitIndex);
+ if (!options.shouldClip || (x_prime >= lowComplexity && x_prime <= highComplexity))
+ x_best = x_prime;
+ else {
+ // Discontinuous piecewise regression
+ x_best = x;
+ }
+ }
+
+ // Iterate from startIndex to endIndex - 1, inclusive
+ for (var i = startIndex; iterationDirection * (endIndex - i) > 0; i += iterationDirection) {
+ var x = getComplexity(samples, i);
+ var y = getFrameLength(samples, i);
+ var xx = x * x;
+ var yx = y * x;
+ var yy = y * y;
+ // a1, b1, etc. is sum from startIndex to i, inclusive
+ a1 += 1;
+ b1 += x;
+ c1 += xx;
+ d1 += y;
+ h1 += yx;
+ k1 += yy;
+ // a2, b2, etc. is sum from i+1 to endIndex, inclusive
+ a2 -= 1;
+ b2 -= x;
+ c2 -= xx;
+ d2 -= y;
+ h2 -= yx;
+ k2 -= yy;
+
+ var A = c1*d1 - b1*h1;
+ var B = a1*h1 - b1*d1;
+ var C = a1*c1 - b1*b1;
+ var D = c2*d2 - b2*h2;
+ var E = a2*h2 - b2*d2;
+ var F = a2*c2 - b2*b2;
+ var s1 = options.s1 !== undefined ? options.s1 : (A / C);
+ var t1 = options.t1 !== undefined ? options.t1 : (B / C);
+ var s2 = options.s2 !== undefined ? options.s2 : (D / F);
+ var t2 = options.t2 !== undefined ? options.t2 : (E / F);
+ // Assumes that the two segments meet
+ var x_prime = (s1 - s2) / (t2 - t1);
+
+ var error1 = (k1 + a1*s1*s1 + c1*t1*t1 - 2*d1*s1 - 2*h1*t1 + 2*b1*s1*t1) || Number.MAX_VALUE;
+ var error2 = (k2 + a2*s2*s2 + c2*t2*t2 - 2*d2*s2 - 2*h2*t2 + 2*b2*s2*t2) || Number.MAX_VALUE;
+
+ if (i == startIndex) {
+ setBest(s1, t1, error1, s2, t2, error2, i, x_prime, x);
+ continue;
+ }
+
+ if (C == 0 || F == 0)
+ continue;
+
+ // Projected point is not between this and the next sample
+ if (x_prime > getComplexity(samples, i + iterationDirection) || x_prime < x) {
+ // Calculate lambda, which divides the weight of this sample between the two lines
+
+ // These values remove the influence of this sample
+ var I = c1 - 2*b1*x + a1*xx;
+ var H = C - I;
+ var G = A + B*x - C*y;
+
+ var J = D + E*x - F*y;
+ var K = c2 - 2*b2*x + a2*xx;
+
+ var lambda = (G*F + G*K - H*J) / (I*J + G*K);
+ if (lambda > 0 && lambda < 1) {
+ var lambda1 = 1 - lambda;
+ s1 = options.s1 !== undefined ? options.s1 : ((A - lambda1*(-h1*x + d1*xx + c1*y - b1*yx)) / (C - lambda1*I));
+ t1 = options.t1 !== undefined ? options.t1 : ((B - lambda1*(h1 - d1*x - b1*y + a1*yx)) / (C - lambda1*I));
+ s2 = options.s2 !== undefined ? options.s2 : ((D + lambda1*(-h2*x + d2*xx + c2*y - b2*yx)) / (F + lambda1*K));
+ t2 = options.t2 !== undefined ? options.t2 : ((E + lambda1*(h2 - d2*x - b2*y + a2*yx)) / (F + lambda1*K));
+ x_prime = (s1 - s2) / (t2 - t1);
+
+ error1 = ((k1 + a1*s1*s1 + c1*t1*t1 - 2*d1*s1 - 2*h1*t1 + 2*b1*s1*t1) - lambda1 * Math.pow(y - (s1 + t1*x), 2)) || Number.MAX_VALUE;
+ error2 = ((k2 + a2*s2*s2 + c2*t2*t2 - 2*d2*s2 - 2*h2*t2 + 2*b2*s2*t2) + lambda1 * Math.pow(y - (s2 + t2*x), 2)) || Number.MAX_VALUE;
+ } else if (t1 != t2)
+ continue;
+ }
+
+ if (error1 + error2 < error1_best + error2_best)
+ setBest(s1, t1, error1, s2, t2, error2, i, x_prime, x);
+ }
+
+ return {
+ complexity: x_best,
+ s1: s1_best,
+ t1: t1_best,
+ stdev1: Math.sqrt(error1_best / n1_best),
+ s2: s2_best,
+ t2: t2_best,
+ stdev2: Math.sqrt(error2_best / n2_best),
+ error: error1_best + error2_best,
+ n1: n1_best,
+ n2: n2_best
+ };
+ }
+});
+
+Utilities.extendObject(Regression, {
+ bootstrap: function(samples, iterationCount, processResample, confidencePercentage)
+ {
+ var sampleLength = samples.length;
+ var resample = new Array(sampleLength);
+
+ var bootstrapEstimator = new Experiment;
+ var bootstrapData = new Array(iterationCount);
+
+ Pseudo.resetRandomSeed();
+ for (var i = 0; i < iterationCount; ++i) {
+ for (var j = 0; j < sampleLength; ++j)
+ resample[j] = samples[Math.floor(Pseudo.random() * sampleLength)];
+
+ var resampleResult = processResample(resample);
+ bootstrapEstimator.sample(resampleResult);
+ bootstrapData[i] = resampleResult;
+ }
+
+ bootstrapData.sort(function(a, b) { return a - b; });
+ return {
+ confidenceLow: bootstrapData[Math.round((iterationCount - 1) * (1 - confidencePercentage) / 2)],
+ confidenceHigh: bootstrapData[Math.round((iterationCount - 1) * (1 + confidencePercentage) / 2)],
+ median: bootstrapData[Math.round(iterationCount / 2)],
+ mean: bootstrapEstimator.mean(),
+ data: bootstrapData,
+ confidencePercentage: confidencePercentage
+ };
+ }
+});
diff --git a/third_party/webkit/PerformanceTests/MotionMark/resources/strings.js b/third_party/webkit/PerformanceTests/MotionMark/resources/strings.js
new file mode 100644
index 0000000000..b58f67e991
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/resources/strings.js
@@ -0,0 +1,51 @@
+var Strings = {
+ text: {
+ testName: "Test Name",
+ score: "Score"
+ },
+ json: {
+ marks: "marks",
+ samplingStartTimeOffset: "Start sampling",
+ samplingEndTimeOffset: "End sampling",
+
+ samples: "samples",
+ dataFieldMap: "dataFieldMap",
+ controller: "controller",
+ time: "time",
+ complexity: "complexity",
+ complexityAverage: "complexityAverage",
+ frameLength: "frameLength",
+ smoothedFrameLength: "smoothedFrameLength",
+
+ result: "result",
+ configuration: "configuration",
+ score: "score",
+ scoreLowerBound: "scoreLowerBound",
+ scoreUpperBound: "scoreUpperBound",
+ bootstrap: "bootstrap",
+ measurements: {
+ average: "average",
+ concern: "concern",
+ stdev: "stdev",
+ percent: "percent"
+ },
+
+ regressions: {
+ startIndex: "startIndex",
+ endIndex: "endIndex",
+ segment1: "segment1",
+ segment2: "segment2",
+ profile: "profile"
+ },
+
+ profiles: {
+ slope: "slope",
+ flat: "flat"
+ },
+
+ results: {
+ iterations: "iterationsResults",
+ tests: "testsResults"
+ }
+ }
+};
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/3d/resources/webgl.js b/third_party/webkit/PerformanceTests/MotionMark/tests/3d/resources/webgl.js
new file mode 100644
index 0000000000..58f5df385e
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/3d/resources/webgl.js
@@ -0,0 +1,184 @@
+(function() {
+
+WebGLStage = Utilities.createSubclass(Stage,
+ function(element, options)
+ {
+ Stage.call(this);
+ },
+ {
+
+ initialize: function(benchmark, options)
+ {
+ Stage.prototype.initialize.call(this, benchmark, options);
+
+ this._numTriangles = 0;
+ this._bufferSize = 0;
+
+ this._gl = this.element.getContext("webgl");
+ var gl = this._gl;
+
+ gl.clearColor(0.5, 0.5, 0.5, 1);
+
+ // Create the vertex shader object.
+ var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+
+ // The source code for the shader is extracted from the <script> element above.
+ gl.shaderSource(vertexShader, this._getFunctionSource("vertex"));
+
+ // Compile the shader.
+ gl.compileShader(vertexShader);
+ if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
+ // We failed to compile. Output to the console and quit.
+ console.error("Vertex Shader failed to compile.");
+ console.error(gl.getShaderInfoLog(vertexShader));
+ return;
+ }
+
+ // Now do the fragment shader.
+ var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fragmentShader, this._getFunctionSource("fragment"));
+ gl.compileShader(fragmentShader);
+ if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
+ console.error("Fragment Shader failed to compile.");
+ console.error(gl.getShaderInfoLog(fragmentShader));
+ return;
+ }
+
+ // We have two compiled shaders. Time to make the program.
+ var program = gl.createProgram();
+ gl.attachShader(program, vertexShader);
+ gl.attachShader(program, fragmentShader);
+ gl.linkProgram(program);
+
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
+ console.error("Unable to link shaders into program.");
+ return;
+ }
+
+ // Our program has two inputs. We have a single uniform "color",
+ // and one vertex attribute "position".
+
+ gl.useProgram(program);
+ this._uScale = gl.getUniformLocation(program, "scale");
+ this._uTime = gl.getUniformLocation(program, "time");
+ this._uOffsetX = gl.getUniformLocation(program, "offsetX");
+ this._uOffsetY = gl.getUniformLocation(program, "offsetY");
+ this._uScalar = gl.getUniformLocation(program, "scalar");
+ this._uScalarOffset = gl.getUniformLocation(program, "scalarOffset");
+
+ this._aPosition = gl.getAttribLocation(program, "position");
+ gl.enableVertexAttribArray(this._aPosition);
+
+ this._aColor = gl.getAttribLocation(program, "color");
+ gl.enableVertexAttribArray(this._aColor);
+
+ this._positionData = new Float32Array([
+ // x y z 1
+ 0, 0.1, 0, 1,
+ -0.1, -0.1, 0, 1,
+ 0.1, -0.1, 0, 1
+ ]);
+ this._positionBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, this._positionBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, this._positionData, gl.STATIC_DRAW);
+
+ this._colorData = new Float32Array([
+ 1, 0, 0, 1,
+ 0, 1, 0, 1,
+ 0, 0, 1, 1
+ ]);
+ this._colorBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, this._colorBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, this._colorData, gl.STATIC_DRAW);
+
+ this._resetIfNecessary();
+ },
+
+ _getFunctionSource: function(id)
+ {
+ return document.getElementById(id).text;
+ },
+
+ _resetIfNecessary: function()
+ {
+ if (this._numTriangles <= this._bufferSize)
+ return;
+
+ if (!this._bufferSize)
+ this._bufferSize = 128;
+
+ while (this._numTriangles > this._bufferSize)
+ this._bufferSize *= 4;
+
+ this._uniformData = new Float32Array(this._bufferSize * 6);
+ for (var i = 0; i < this._bufferSize; ++i) {
+ this._uniformData[i * 6 + 0] = Stage.random(0.2, 0.4);
+ this._uniformData[i * 6 + 1] = 0;
+ this._uniformData[i * 6 + 2] = Stage.random(-0.9, 0.9);
+ this._uniformData[i * 6 + 3] = Stage.random(-0.9, 0.9);
+ this._uniformData[i * 6 + 4] = Stage.random(0.5, 2);
+ this._uniformData[i * 6 + 5] = Stage.random(0, 10);
+ }
+ },
+
+ tune: function(count)
+ {
+ if (!count)
+ return;
+
+ this._numTriangles += count;
+ this._numTriangles = Math.max(this._numTriangles, 0);
+
+ this._resetIfNecessary();
+ },
+
+ animate: function(timeDelta)
+ {
+ var gl = this._gl;
+
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ if (!this._startTime)
+ this._startTime = Stage.dateCounterValue(1000);
+ var elapsedTime = Stage.dateCounterValue(1000) - this._startTime;
+
+ for (var i = 0; i < this._numTriangles; ++i) {
+
+ this._uniformData[i * 6 + 1] = elapsedTime;
+
+ var uniformDataOffset = i * 6;
+ gl.uniform1f(this._uScale, this._uniformData[uniformDataOffset++]);
+ gl.uniform1f(this._uTime, this._uniformData[uniformDataOffset++]);
+ gl.uniform1f(this._uOffsetX, this._uniformData[uniformDataOffset++]);
+ gl.uniform1f(this._uOffsetY, this._uniformData[uniformDataOffset++]);
+ gl.uniform1f(this._uScalar, this._uniformData[uniformDataOffset++]);
+ gl.uniform1f(this._uScalarOffset, this._uniformData[uniformDataOffset++]);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, this._positionBuffer);
+ gl.vertexAttribPointer(this._aPosition, 4, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, this._colorBuffer);
+ gl.vertexAttribPointer(this._aColor, 4, gl.FLOAT, false, 0, 0);
+
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
+ }
+
+ },
+
+ complexity: function()
+ {
+ return this._numTriangles;
+ }
+ }
+);
+
+WebGLBenchmark = Utilities.createSubclass(Benchmark,
+ function(options)
+ {
+ Benchmark.call(this, new WebGLStage(), options);
+ }
+);
+
+window.benchmarkClass = WebGLBenchmark;
+
+})();
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/3d/webgl.html b/third_party/webkit/PerformanceTests/MotionMark/tests/3d/webgl.html
new file mode 100644
index 0000000000..cf6442a07a
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/3d/webgl.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="../resources/stage.css">
+</head>
+<body>
+ <canvas id="stage"></canvas>
+ <script id="vertex" type="x-shader/x-glsl">
+attribute vec4 position;
+attribute vec4 color;
+
+uniform float scale;
+uniform float time;
+uniform float offsetX;
+uniform float offsetY;
+uniform float scalar;
+uniform float scalarOffset;
+
+varying vec4 v_color;
+
+void main() {
+
+ float fade = mod(scalarOffset + time * scalar / 10.0, 1.0);
+
+ if (fade < 0.5) {
+ fade = fade * 2.0;
+ } else {
+ fade = (1.0 - fade) * 2.0;
+ }
+
+ float xpos = position.x * scale;
+ float ypos = position.y * scale;
+
+ float angle = 3.14159 * 2.0 * fade;
+ float xrot = xpos * cos(angle) - ypos * sin(angle);
+ float yrot = xpos * sin(angle) + ypos * cos(angle);
+
+ xpos = xrot + offsetX;
+ ypos = yrot + offsetY;
+
+ v_color = vec4(fade, 1.0 - fade, 0.0, 1.0) + color;
+ gl_Position = vec4(xpos, ypos, 0.0, 1.0);
+}
+ </script>
+ <script id="fragment" type="x-shader/x-glsl">
+#ifdef GL_ES
+precision mediump float;
+#endif
+
+varying vec4 v_color;
+
+void main() {
+ gl_FragColor = v_color;
+}
+ </script>
+ <script src="../../resources/strings.js"></script>
+ <script src="../../resources/extensions.js"></script>
+ <script src="../../resources/statistics.js"></script>
+ <script src="../resources/math.js"></script>
+ <script src="../resources/main.js"></script>
+ <script src="resources/webgl.js"></script>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-canvas-images.html b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-canvas-images.html
new file mode 100644
index 0000000000..864c19adcd
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-canvas-images.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="../resources/stage.css">
+ <style>
+ img.hidden {
+ position: absolute;
+ visibility: hidden;
+ }
+ </style>
+</head>
+<body>
+ <img class="hidden" src="../resources/yin-yang.svg">
+ <img class="hidden" src="../resources/yin-yang.png">
+ <canvas id="stage"></canvas>
+ <script src="../../resources/strings.js"></script>
+ <script src="../../resources/extensions.js"></script>
+ <script src="../../resources/statistics.js"></script>
+ <script src="../resources/math.js"></script>
+ <script src="../resources/main.js"></script>
+ <script src="resources/bouncing-particles.js"></script>
+ <script src="resources/bouncing-canvas-particles.js"></script>
+ <script src="resources/bouncing-canvas-images.js"></script>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-canvas-shapes.html b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-canvas-shapes.html
new file mode 100644
index 0000000000..c759d45c08
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-canvas-shapes.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="../resources/stage.css">
+</head>
+<body>
+ <canvas id="stage"></canvas>
+ <script src="../../resources/strings.js"></script>
+ <script src="../../resources/extensions.js"></script>
+ <script src="../../resources/statistics.js"></script>
+ <script src="../resources/math.js"></script>
+ <script src="../resources/main.js"></script>
+ <script src="resources/bouncing-particles.js"></script>
+ <script src="resources/bouncing-canvas-particles.js"></script>
+ <script src="resources/bouncing-canvas-shapes.js"></script>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-css-images.html b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-css-images.html
new file mode 100644
index 0000000000..058de486de
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-css-images.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="../resources/stage.css">
+ <style>
+ img {
+ position: absolute;
+ }
+ </style>
+</head>
+<body>
+ <div id="stage"></div>
+ <script src="../../resources/strings.js"></script>
+ <script src="../../resources/extensions.js"></script>
+ <script src="../../resources/statistics.js"></script>
+ <script src="../resources/math.js"></script>
+ <script src="../resources/main.js"></script>
+ <script src="resources/bouncing-particles.js"></script>
+ <script src="resources/bouncing-css-images.js"></script>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-css-shapes.html b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-css-shapes.html
new file mode 100644
index 0000000000..0c1248f490
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-css-shapes.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="../resources/stage.css">
+ <style>
+ .circle {
+ position: absolute;
+ background-color: #000000;
+ border-radius: 50% 50%;
+ }
+ .rect {
+ position: absolute;
+ background-color: #000000;
+ }
+ .star {
+ -webkit-clip-path: polygon(50% 0%, 38% 38%, 0% 38%, 30% 60%, 18% 100%, 50% 75%, 82% 100%, 70% 60%, 100% 38%, 62% 38%);
+ -ms-clip-path: polygon(50% 0%, 38% 38%, 0% 38%, 30% 60%, 18% 100%, 50% 75%, 82% 100%, 70% 60%, 100% 38%, 62% 38%);
+ clip-path: polygon(50% 0%, 38% 38%, 0% 38%, 30% 60%, 18% 100%, 50% 75%, 82% 100%, 70% 60%, 100% 38%, 62% 38%);
+ }
+ </style>
+</head>
+<body>
+ <div id="stage"></div>
+ <script src="../../resources/strings.js"></script>
+ <script src="../../resources/extensions.js"></script>
+ <script src="../../resources/statistics.js"></script>
+ <script src="../resources/math.js"></script>
+ <script src="../resources/main.js"></script>
+ <script src="resources/bouncing-particles.js"></script>
+ <script src="resources/bouncing-css-shapes.js"></script>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-svg-images.html b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-svg-images.html
new file mode 100644
index 0000000000..2b6a0b9db5
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-svg-images.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="../resources/stage.css">
+</head>
+<body>
+ <svg id="stage"></svg>
+ <script src="../../resources/strings.js"></script>
+ <script src="../../resources/extensions.js"></script>
+ <script src="../../resources/statistics.js"></script>
+ <script src="../resources/math.js"></script>
+ <script src="../resources/main.js"></script>
+ <script src="resources/bouncing-particles.js"></script>
+ <script src="resources/bouncing-svg-particles.js"></script>
+ <script src="resources/bouncing-svg-images.js"></script>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-svg-shapes.html b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-svg-shapes.html
new file mode 100644
index 0000000000..a821231672
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-svg-shapes.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="../resources/stage.css">
+</head>
+<body>
+ <svg id="stage"></svg>
+ <script src="../../resources/strings.js"></script>
+ <script src="../../resources/extensions.js"></script>
+ <script src="../../resources/statistics.js"></script>
+ <script src="../resources/math.js"></script>
+ <script src="../resources/main.js"></script>
+ <script src="resources/bouncing-particles.js"></script>
+ <script src="resources/bouncing-svg-particles.js"></script>
+ <script src="resources/bouncing-svg-shapes.js"></script>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-tagged-images.html b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-tagged-images.html
new file mode 100644
index 0000000000..f67f14ad36
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-tagged-images.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <style>
+ img {
+ position: absolute;
+ }
+ </style>
+ <link rel="stylesheet" type="text/css" href="../resources/stage.css">
+
+ <script src="../../resources/strings.js"></script>
+ <script src="../../resources/extensions.js"></script>
+ <script src="../../resources/statistics.js"></script>
+ <script src="../resources/math.js"></script>
+ <script src="../resources/main.js"></script>
+ <script src="resources/bouncing-particles.js"></script>
+ <script src="resources/bouncing-tagged-images.js"></script>
+</head>
+<body>
+ <div id="stage"></div>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-canvas-images.js b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-canvas-images.js
new file mode 100644
index 0000000000..5fba5ad761
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-canvas-images.js
@@ -0,0 +1,47 @@
+(function() {
+
+BouncingCanvasImage = Utilities.createSubclass(BouncingCanvasParticle,
+ function(stage)
+ {
+ BouncingCanvasParticle.call(this, stage, "image");
+ this._imageElement = stage.imageElement;
+ }, {
+
+ _draw: function()
+ {
+ this.context.save();
+ this.applyRotation();
+ this.context.drawImage(this._imageElement, 0, 0, this.size.x, this.size.y);
+ this.context.restore();
+ }
+});
+
+BouncingCanvasImagesStage = Utilities.createSubclass(BouncingCanvasParticlesStage,
+ function()
+ {
+ BouncingCanvasParticlesStage.call(this);
+ }, {
+
+ initialize: function(benchmark, options)
+ {
+ BouncingCanvasParticlesStage.prototype.initialize.call(this, benchmark, options);
+ var imageSrc = options["imageSrc"] || "resources/yin-yang.svg";
+ this.imageElement = document.querySelector(".hidden[src=\"" + imageSrc + "\"]");
+ },
+
+ createParticle: function()
+ {
+ return new BouncingCanvasImage(this);
+ }
+});
+
+BouncingCanvasImagesBenchmark = Utilities.createSubclass(Benchmark,
+ function(options)
+ {
+ Benchmark.call(this, new BouncingCanvasImagesStage(), options);
+ }
+);
+
+window.benchmarkClass = BouncingCanvasImagesBenchmark;
+
+})();
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-canvas-particles.js b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-canvas-particles.js
new file mode 100644
index 0000000000..0a76ba05c3
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-canvas-particles.js
@@ -0,0 +1,88 @@
+BouncingCanvasParticle = Utilities.createSubclass(BouncingParticle,
+ function(stage, shape)
+ {
+ BouncingParticle.call(this, stage);
+ this.context = stage.context;
+ this._shape = shape;
+ this._clip = stage.clip;
+ }, {
+
+ applyRotation: function()
+ {
+ if (this._shape == "circle")
+ return;
+
+ this.context.translate(this.size.x / 2, this.size.y / 2);
+ this.context.rotate(this.rotater.degree() * Math.PI / 180);
+ this.context.translate(-this.size.x / 2, -this.size.y / 2);
+ },
+
+ applyClipping: function()
+ {
+ var clipPoints = BouncingCanvasParticle.clips[this._clip];
+ if (!clipPoints)
+ return;
+
+ this.context.beginPath();
+ clipPoints.forEach(function(point, index) {
+ var point = this.size.multiply(point);
+ if (!index)
+ this.context.moveTo(point.x, point.y);
+ else
+ this.context.lineTo(point.x, point.y);
+ }, this);
+
+ this.context.closePath();
+ this.context.clip();
+ },
+
+ _draw: function()
+ {
+ throw "Not implemented";
+ },
+
+ animate: function(timeDelta)
+ {
+ BouncingParticle.prototype.animate.call(this, timeDelta);
+ this.context.save();
+ this.context.translate(this.position.x, this.position.y);
+ this._draw();
+ this.context.restore();
+ }
+});
+
+BouncingCanvasParticle.clips = {
+ star: [
+ new Point(0.50, 0.00),
+ new Point(0.38, 0.38),
+ new Point(0.00, 0.38),
+ new Point(0.30, 0.60),
+ new Point(0.18, 1.00),
+ new Point(0.50, 0.75),
+ new Point(0.82, 1.00),
+ new Point(0.70, 0.60),
+ new Point(1.00, 0.38),
+ new Point(0.62, 0.38)
+ ]
+};
+
+BouncingCanvasParticlesStage = Utilities.createSubclass(BouncingParticlesStage,
+ function()
+ {
+ BouncingParticlesStage.call(this);
+ }, {
+
+ initialize: function(benchmark, options)
+ {
+ BouncingParticlesStage.prototype.initialize.call(this, benchmark, options);
+ this.context = this.element.getContext("2d");
+ },
+
+ animate: function(timeDelta)
+ {
+ this.context.clearRect(0, 0, this.size.x, this.size.y);
+ this.particles.forEach(function(particle) {
+ particle.animate(timeDelta);
+ });
+ }
+});
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-canvas-shapes.js b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-canvas-shapes.js
new file mode 100644
index 0000000000..49a31cf40d
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-canvas-shapes.js
@@ -0,0 +1,87 @@
+(function() {
+
+BouncingCanvasShape = Utilities.createSubclass(BouncingCanvasParticle,
+ function(stage)
+ {
+ BouncingCanvasParticle.call(this, stage, stage.shape);
+ this._fill = stage.fill;
+ this._color0 = Stage.randomColor();
+ this._color1 = Stage.randomColor();
+ }, {
+
+ _applyFill: function()
+ {
+ switch (this._fill) {
+ case "gradient":
+ var gradient = this.context.createLinearGradient(0, 0, this.size.width, 0);
+ gradient.addColorStop(0, this._color0);
+ gradient.addColorStop(1, this._color1);
+ this.context.fillStyle = gradient;
+ break;
+
+ case "solid":
+ default:
+ this.context.fillStyle = this._color0;
+ break;
+ }
+ },
+
+ _drawShape: function()
+ {
+ this.context.beginPath();
+
+ switch (this._shape) {
+ case "rect":
+ this.context.rect(0, 0, this.size.width, this.size.height);
+ break;
+
+ case "circle":
+ default:
+ var center = this.size.center;
+ var radius = Math.min(this.size.x, this.size.y) / 2;
+ this.context.arc(center.x, center.y, radius, 0, Math.PI * 2, true);
+ break;
+ }
+
+ this.context.fill();
+ },
+
+ _draw: function()
+ {
+ this.context.save();
+ this._applyFill();
+ this.applyRotation();
+ this.applyClipping();
+ this._drawShape();
+ this.context.restore();
+ }
+});
+
+BouncingCanvasShapesStage = Utilities.createSubclass(BouncingCanvasParticlesStage,
+ function ()
+ {
+ BouncingCanvasParticlesStage.call(this);
+ }, {
+
+ initialize: function(benchmark, options)
+ {
+ BouncingCanvasParticlesStage.prototype.initialize.call(this, benchmark, options);
+ this.parseShapeParameters(options);
+ },
+
+ createParticle: function()
+ {
+ return new BouncingCanvasShape(this);
+ }
+});
+
+BouncingCanvasShapesBenchmark = Utilities.createSubclass(Benchmark,
+ function(options)
+ {
+ Benchmark.call(this, new BouncingCanvasShapesStage(), options);
+ }
+);
+
+window.benchmarkClass = BouncingCanvasShapesBenchmark;
+
+})(); \ No newline at end of file
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-css-images.js b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-css-images.js
new file mode 100644
index 0000000000..ce9a48c276
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-css-images.js
@@ -0,0 +1,61 @@
+(function() {
+
+BouncingCssImage = Utilities.createSubclass(BouncingParticle,
+ function(stage)
+ {
+ BouncingParticle.call(this, stage);
+
+ this.element = document.createElement("img");
+ this.element.style.width = this.size.x + "px";
+ this.element.style.height = this.size.y + "px";
+ this.element.setAttribute("src", stage.imageSrc);
+
+ stage.element.appendChild(this.element);
+ this._move();
+ }, {
+
+ _move: function()
+ {
+ this.element.style.transform = "translate(" + this.position.x + "px," + this.position.y + "px) " + this.rotater.rotateZ();
+ },
+
+ animate: function(timeDelta)
+ {
+ BouncingParticle.prototype.animate.call(this, timeDelta);
+ this._move();
+ }
+});
+
+BouncingCssImagesStage = Utilities.createSubclass(BouncingParticlesStage,
+ function()
+ {
+ BouncingParticlesStage.call(this);
+ }, {
+
+ initialize: function(benchmark, options)
+ {
+ BouncingParticlesStage.prototype.initialize.call(this, benchmark, options);
+ this.imageSrc = options["imageSrc"] || "../resources/yin-yang.svg";
+ },
+
+ createParticle: function()
+ {
+ return new BouncingCssImage(this);
+ },
+
+ particleWillBeRemoved: function(particle)
+ {
+ particle.element.remove();
+ }
+});
+
+BouncingCssImagesBenchmark = Utilities.createSubclass(Benchmark,
+ function(options)
+ {
+ Benchmark.call(this, new BouncingCssImagesStage(), options);
+ }
+);
+
+window.benchmarkClass = BouncingCssImagesBenchmark;
+
+})();
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-css-shapes.js b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-css-shapes.js
new file mode 100644
index 0000000000..a1f81863f9
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-css-shapes.js
@@ -0,0 +1,86 @@
+(function() {
+
+BouncingCssShape = Utilities.createSubclass(BouncingParticle,
+ function(stage)
+ {
+ BouncingParticle.call(this, stage);
+
+ this.element = this._createSpan(stage);
+
+ switch (stage.fill) {
+ case "solid":
+ default:
+ this.element.style.backgroundColor = Stage.randomColor();
+ break;
+
+ case "gradient":
+ this.element.style.background = "linear-gradient(" + Stage.randomColor() + ", " + Stage.randomColor() + ")";
+ break;
+ }
+
+ if (stage.blend)
+ this.element.style.mixBlendMode = Stage.randomStyleMixBlendMode();
+
+ // Some browsers have not un-prefixed the css filter yet.
+ if (stage.filter)
+ Utilities.setElementPrefixedProperty(this.element, "filter", Stage.randomStyleFilter());
+
+ this._move();
+ }, {
+
+ _createSpan: function(stage)
+ {
+ var span = document.createElement("span");
+ span.className = stage.shape + " " + stage.clip;
+ span.style.width = this.size.x + "px";
+ span.style.height = this.size.y + "px";
+ stage.element.appendChild(span);
+ return span;
+ },
+
+ _move: function()
+ {
+ this.element.style.transform = "translate(" + this.position.x + "px," + this.position.y + "px)" + this.rotater.rotateZ();
+ },
+
+ animate: function(timeDelta)
+ {
+ BouncingParticle.prototype.animate.call(this, timeDelta);
+ this.rotater.next(timeDelta);
+ this._move();
+ }
+});
+
+BouncingCssShapesStage = Utilities.createSubclass(BouncingParticlesStage,
+ function()
+ {
+ BouncingParticlesStage.call(this);
+ }, {
+
+ initialize: function(benchmark, options)
+ {
+ BouncingParticlesStage.prototype.initialize.call(this, benchmark, options);
+ this.parseShapeParameters(options);
+ },
+
+ createParticle: function()
+ {
+ return new BouncingCssShape(this);
+ },
+
+ particleWillBeRemoved: function(particle)
+ {
+ particle.element.remove();
+ }
+});
+
+BouncingCssShapesBenchmark = Utilities.createSubclass(Benchmark,
+ function(options)
+ {
+ Benchmark.call(this, new BouncingCssShapesStage(), options);
+ }
+);
+
+window.benchmarkClass = BouncingCssShapesBenchmark;
+
+})();
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-particles.js b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-particles.js
new file mode 100644
index 0000000000..27e02a7085
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-particles.js
@@ -0,0 +1,123 @@
+function BouncingParticle(stage)
+{
+ this._stageSize = stage.size;
+ this.size = stage.particleSize;
+
+ this.position = Stage.randomPosition(stage.size.subtract(stage.particleSize));
+ this._angle = Stage.randomAngle();
+ this._velocity = Stage.randomVelocity(stage.maxVelocity);
+ this.rotater = Stage.randomRotater();
+}
+
+BouncingParticle.prototype =
+{
+ get center()
+ {
+ return this.position.add(this.size.center);
+ },
+
+ animate: function(timeDelta)
+ {
+ this.position = this.position.move(this._angle, this._velocity, timeDelta);
+ this.rotater.next(timeDelta);
+
+ // If particle is going to move off right side
+ if (this.position.x + this.size.x > this._stageSize.x) {
+ // If direction is East-South, go West-South.
+ if (this._angle >= 0 && this._angle < Math.PI / 2)
+ this._angle = Math.PI - this._angle;
+ // If angle is East-North, go West-North.
+ else if (this._angle > Math.PI / 2 * 3)
+ this._angle = this._angle - (this._angle - Math.PI / 2 * 3) * 2;
+ // Make sure the particle does not go outside the stage boundaries.
+ this.position.x = this._stageSize.x - this.size.x;
+ }
+
+ // If particle is going to move off left side
+ if (this.position.x < 0) {
+ // If angle is West-South, go East-South.
+ if (this._angle > Math.PI / 2 && this._angle < Math.PI)
+ this._angle = Math.PI - this._angle;
+ // If angle is West-North, go East-North.
+ else if (this._angle > Math.PI && this._angle < Math.PI / 2 * 3)
+ this._angle = this._angle + (Math.PI / 2 * 3 - this._angle) * 2;
+ // Make sure the particle does not go outside the stage boundaries.
+ this.position.x = 0;
+ }
+
+ // If particle is going to move off bottom side
+ if (this.position.y + this.size.y > this._stageSize.y) {
+ // If direction is South, go North.
+ if (this._angle > 0 && this._angle < Math.PI)
+ this._angle = Math.PI * 2 - this._angle;
+ // Make sure the particle does not go outside the stage boundaries.
+ this.position.y = this._stageSize.y - this.size.y;
+ }
+
+ // If particle is going to move off top side
+ if (this.position.y < 0) {
+ // If direction is North, go South.
+ if (this._angle > Math.PI && this._angle < Math.PI * 2)
+ this._angle = this._angle - (this._angle - Math.PI) * 2;
+ // Make sure the particle does not go outside the stage boundaries.
+ this.position.y = 0;
+ }
+ }
+}
+
+BouncingParticlesStage = Utilities.createSubclass(Stage,
+ function()
+ {
+ Stage.call(this);
+ this.particles = [];
+ }, {
+
+ initialize: function(benchmark, options)
+ {
+ Stage.prototype.initialize.call(this, benchmark, options);
+ this.particleSize = new Point(parseInt(options["particleWidth"]) || 10, parseInt(options["particleHeight"]) || 10);
+ this.maxVelocity = Math.max(parseInt(options["maxVelocity"]) || 500, 100);
+ },
+
+ parseShapeParameters: function(options)
+ {
+ this.shape = options["shape"] || "circle";
+ this.fill = options["fill"] || "solid";
+ this.clip = options["clip"] || "";
+ this.blend = options["blend"] || false;
+ this.filter = options["filter"] || false;
+ },
+
+ animate: function(timeDelta)
+ {
+ this.particles.forEach(function(particle) {
+ particle.animate(timeDelta);
+ });
+ },
+
+ tune: function(count)
+ {
+ if (count == 0)
+ return;
+
+ if (count > 0) {
+ for (var i = 0; i < count; ++i)
+ this.particles.push(this.createParticle());
+ return;
+ }
+
+ count = Math.min(-count, this.particles.length);
+
+ if (typeof(this.particleWillBeRemoved) == "function") {
+ for (var i = 0; i < count; ++i)
+ this.particleWillBeRemoved(this.particles[this.particles.length - 1 - i]);
+ }
+
+ this.particles.splice(-count, count);
+ },
+
+ complexity: function()
+ {
+ return this.particles.length;
+ }
+});
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-svg-images.js b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-svg-images.js
new file mode 100644
index 0000000000..2239557312
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-svg-images.js
@@ -0,0 +1,43 @@
+(function() {
+
+BouncingSvgImage = Utilities.createSubclass(BouncingSvgParticle,
+ function(stage)
+ {
+ BouncingSvgParticle.call(this, stage, "image");
+
+ var attrs = { x: 0, y: 0, width: this.size.x, height: this.size.y };
+ var xlinkAttrs = { href: stage.imageSrc };
+ this.element = Utilities.createSVGElement("image", attrs, xlinkAttrs, stage.element);
+ this._move();
+ }
+);
+
+BouncingSvgImagesStage = Utilities.createSubclass(BouncingSvgParticlesStage,
+ function()
+ {
+ BouncingSvgParticlesStage.call(this);
+ }, {
+
+ initialize: function(benchmark, options)
+ {
+ BouncingSvgParticlesStage.prototype.initialize.call(this, benchmark, options);
+ this.imageSrc = options["imageSrc"] || "resources/yin-yang.svg";
+ },
+
+ createParticle: function()
+ {
+ return new BouncingSvgImage(this);
+ }
+});
+
+BouncingSvgImagesBenchmark = Utilities.createSubclass(Benchmark,
+ function(options)
+ {
+ Benchmark.call(this, new BouncingSvgImagesStage(), options);
+ }
+);
+
+window.benchmarkClass = BouncingSvgImagesBenchmark;
+
+})();
+
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-svg-particles.js b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-svg-particles.js
new file mode 100644
index 0000000000..0988c42d8e
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-svg-particles.js
@@ -0,0 +1,67 @@
+BouncingSvgParticle = Utilities.createSubclass(BouncingParticle,
+ function(stage, shape)
+ {
+ BouncingParticle.call(this, stage);
+ this._shape = shape;
+ }, {
+
+ _applyClipping: function(stage)
+ {
+ if (stage.clip != "star")
+ return;
+
+ stage.ensureClipStarIsCreated();
+ this.element.setAttribute("clip-path", "url(#star-clip)");
+ },
+
+ _move: function()
+ {
+ var transform = "translate(" + this.position.x + ", " + this.position.y + ")";
+ if (this._shape != "circle")
+ transform += this.rotater.rotate(this.size.center);
+ this.element.setAttribute("transform", transform);
+ },
+
+ animate: function(timeDelta)
+ {
+ BouncingParticle.prototype.animate.call(this, timeDelta);
+ this._move();
+ }
+});
+
+BouncingSvgParticlesStage = Utilities.createSubclass(BouncingParticlesStage,
+ function()
+ {
+ BouncingParticlesStage.call(this);
+ }, {
+
+ _createDefs: function()
+ {
+ return Utilities.createSVGElement("defs", {}, {}, this.element);
+ },
+
+ _ensureDefsIsCreated: function()
+ {
+ return this.element.querySelector("defs") || this._createDefs();
+ },
+
+ _createClipStar: function()
+ {
+ var attrs = { id: "star-clip", clipPathUnits: "objectBoundingBox" };
+ var clipPath = Utilities.createSVGElement("clipPath", attrs, {}, this._ensureDefsIsCreated());
+
+ attrs = { d: "M.50,0L.38,.38L0,.38L.30,.60L.18,1L.50,.75L.82,1L.70,.60L1,.38L.62,.38z" };
+ Utilities.createSVGElement("path", attrs, {}, clipPath);
+ return clipPath;
+ },
+
+ ensureClipStarIsCreated: function()
+ {
+ return this.element.querySelector("#star-clip") || this._createClipStar();
+ },
+
+ particleWillBeRemoved: function(particle)
+ {
+ particle.element.remove();
+ }
+});
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-svg-shapes.js b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-svg-shapes.js
new file mode 100644
index 0000000000..14c917cc31
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-svg-shapes.js
@@ -0,0 +1,101 @@
+(function() {
+
+BouncingSvgShape = Utilities.createSubclass(BouncingSvgParticle,
+ function(stage)
+ {
+ BouncingSvgParticle.call(this, stage, stage.shape);
+ this._fill = stage.fill;
+
+ this._createShape(stage);
+ this._applyClipping(stage);
+ this._applyFill(stage);
+
+ this._move();
+ }, {
+
+ _createShape: function(stage)
+ {
+ switch (this._shape) {
+ case "rect":
+ var attrs = { x: 0, y: 0, width: this.size.x, height: this.size.y };
+ this.element = Utilities.createSVGElement("rect", attrs, {}, stage.element);
+ break;
+
+ case "circle":
+ default:
+ var attrs = { cx: this.size.x / 2, cy: this.size.y / 2, r: Math.min(this.size.x, this.size.y) / 2 };
+ this.element = Utilities.createSVGElement("circle", attrs, {}, stage.element);
+ break;
+ }
+ },
+
+ _applyFill: function(stage)
+ {
+ switch (this._fill) {
+ case "gradient":
+ var gradient = stage.createGradient(2);
+ this.element.setAttribute("fill", "url(#" + gradient.getAttribute("id") + ")");
+ break;
+
+ case "solid":
+ default:
+ this.element.setAttribute("fill", Stage.randomColor());
+ break;
+ }
+ }
+});
+
+BouncingSvgShapesStage = Utilities.createSubclass(BouncingSvgParticlesStage,
+ function()
+ {
+ BouncingSvgParticlesStage.call(this);
+ }, {
+
+ initialize: function(benchmark, options)
+ {
+ BouncingSvgParticlesStage.prototype.initialize.call(this, benchmark, options);
+ this.parseShapeParameters(options);
+ this._gradientsCount = 0;
+ },
+
+ createGradient: function(stops)
+ {
+ var attrs = { id: "gradient-" + ++this._gradientsCount };
+ var gradient = Utilities.createSVGElement("linearGradient", attrs, {}, this._ensureDefsIsCreated());
+
+ for (var i = 0; i < stops; ++i) {
+ attrs = { offset: i * 100 / (stops - 1) + "%", 'stop-color': Stage.randomColor() };
+ Utilities.createSVGElement("stop", attrs, {}, gradient);
+ }
+
+ return gradient;
+ },
+
+ createParticle: function()
+ {
+ return new BouncingSvgShape(this);
+ },
+
+ particleWillBeRemoved: function(particle)
+ {
+ BouncingSvgParticlesStage.prototype.particleWillBeRemoved.call(this, particle);
+
+ var fill = particle.element.getAttribute("fill");
+ if (fill.indexOf("url(#") != 0)
+ return;
+
+ var gradient = this.element.querySelector(fill.substring(4, fill.length - 1));
+ this._ensureDefsIsCreated().removeChild(gradient);
+ }
+});
+
+BouncingSvgShapesBenchmark = Utilities.createSubclass(Benchmark,
+ function(options)
+ {
+ Benchmark.call(this, new BouncingSvgShapesStage(), options);
+ }
+);
+
+window.benchmarkClass = BouncingSvgShapesBenchmark;
+
+})();
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-tagged-images.js b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-tagged-images.js
new file mode 100644
index 0000000000..1ef6a091d2
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-tagged-images.js
@@ -0,0 +1,106 @@
+(function() {
+
+BouncingTaggedImage = Utilities.createSubclass(BouncingParticle,
+ function(stage)
+ {
+ BouncingParticle.call(this, stage);
+
+ this.element = document.createElement("img");
+ this.element.style.width = this.size.x + "px";
+ this.element.style.height = this.size.y + "px";
+ this.element.setAttribute("src", Stage.randomElementInArray(stage.images).src);
+
+ stage.element.appendChild(this.element);
+ this._move();
+ }, {
+
+ _move: function()
+ {
+ this.element.style.transform = "translate(" + this.position.x + "px," + this.position.y + "px) " + this.rotater.rotateZ();
+ },
+
+ animate: function(timeDelta)
+ {
+ BouncingParticle.prototype.animate.call(this, timeDelta);
+ this._move();
+ }
+});
+
+BouncingTaggedImagesStage = Utilities.createSubclass(BouncingParticlesStage,
+
+ function()
+ {
+ BouncingParticlesStage.call(this);
+ }, {
+
+ imageSrcs: [
+ "image1",
+ "image2",
+ "image3",
+ "image4",
+ "image5",
+ ],
+ images: [],
+
+ initialize: function(benchmark, options)
+ {
+ BouncingParticlesStage.prototype.initialize.call(this, benchmark, options);
+
+ var lastPromise;
+ var images = this.images;
+ this.imageSrcs.forEach(function(imageSrc) {
+ var promise = this._loadImage("resources/" + imageSrc + ".jpg");
+ if (!lastPromise)
+ lastPromise = promise;
+ else {
+ lastPromise = lastPromise.then(function(img) {
+ images.push(img);
+ return promise;
+ });
+ }
+ }, this);
+
+ lastPromise.then(function(img) {
+ images.push(img);
+ benchmark.readyPromise.resolve();
+ });
+ },
+
+ _loadImage: function(src) {
+ var img = new Image;
+ var promise = new SimplePromise;
+
+ img.onload = function(e) {
+ promise.resolve(e.target);
+ };
+
+ img.src = src;
+ return promise;
+ },
+
+ createParticle: function()
+ {
+ return new BouncingTaggedImage(this);
+ },
+
+ particleWillBeRemoved: function(particle)
+ {
+ particle.element.remove();
+ }
+});
+
+BouncingTaggedImagesBenchmark = Utilities.createSubclass(Benchmark,
+ function(options)
+ {
+ Benchmark.call(this, new BouncingTaggedImagesStage(), options);
+ }, {
+
+ waitUntilReady: function() {
+ this.readyPromise = new SimplePromise;
+ return this.readyPromise;
+ }
+});
+
+window.benchmarkClass = BouncingTaggedImagesBenchmark;
+
+})();
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image1.jpg b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image1.jpg
new file mode 100644
index 0000000000..ea7a4c1303
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image1.jpg
Binary files differ
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image2.jpg b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image2.jpg
new file mode 100644
index 0000000000..697272dcb0
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image2.jpg
Binary files differ
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image3.jpg b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image3.jpg
new file mode 100644
index 0000000000..6e5964e7a9
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image3.jpg
Binary files differ
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image4.jpg b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image4.jpg
new file mode 100644
index 0000000000..806f548c44
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image4.jpg
Binary files differ
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image5.jpg b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image5.jpg
new file mode 100644
index 0000000000..d7971f6bcb
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image5.jpg
Binary files differ
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/dom/compositing-transforms.html b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/compositing-transforms.html
new file mode 100644
index 0000000000..6d5b0bf5e6
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/compositing-transforms.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="../resources/stage.css">
+ <style>
+ img {
+ position: absolute;
+ width: 80px;
+ height: 80px;
+ }
+ </style>
+</head>
+<body>
+ <div id="stage"></div>
+ <script src="../../resources/strings.js"></script>
+ <script src="../../resources/extensions.js"></script>
+ <script src="../../resources/statistics.js"></script>
+ <script src="../resources/math.js"></script>
+ <script src="../resources/main.js"></script>
+ <script src="../bouncing-particles/resources/bouncing-particles.js"></script>
+ <script src="resources/compositing-transforms.js"></script>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/dom/focus.html b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/focus.html
new file mode 100644
index 0000000000..02264d746f
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/focus.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="../resources/stage.css">
+ <style type="text/css">
+
+ #stage {
+ background-color: #201A1F;
+ z-index: -10000;
+ }
+
+ #stage > div {
+ position: absolute;
+ overflow: hidden;
+ }
+ #stage div div {
+ position: absolute;
+ background-color: #DEDADD;
+ border-radius: 50%;
+ }
+
+ #center-text {
+ font-size: 90%;
+ transform: translate3d(-50%, -50%, 0);
+ }
+
+ #center-text span {
+ position: absolute;
+ color: #201A1F;
+ font-weight: 400;
+ font-size: 2em;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ }
+
+ </style>
+</head>
+<body>
+ <div id="stage">
+ <div id="center-text"><div><span>focus</span></div></div>
+ </div>
+ <script src="../../resources/strings.js"></script>
+ <script src="../../resources/extensions.js"></script>
+ <script src="../../resources/statistics.js"></script>
+ <script src="../resources/math.js"></script>
+ <script src="../resources/main.js"></script>
+ <script src="resources/focus.js"></script>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/dom/leaves.html b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/leaves.html
new file mode 100644
index 0000000000..625882ebef
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/leaves.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="../resources/stage.css">
+ <style>
+ #stage {
+ background-color: #23282B;
+ }
+ #stage img {
+ position: absolute;
+ }
+ </style>
+</head>
+<body>
+ <div id="stage"></div>
+ <script src="../../resources/strings.js"></script>
+ <script src="../../resources/extensions.js"></script>
+ <script src="../../resources/statistics.js"></script>
+ <script src="../resources/math.js"></script>
+ <script src="../resources/main.js"></script>
+ <script src="../master/resources/particles.js"></script>
+ <script src="../master/resources/leaves.js"></script>
+ <script src="resources/leaves.js"></script>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/dom/particles.html b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/particles.html
new file mode 100644
index 0000000000..fdc09399c9
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/particles.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="../resources/stage.css">
+ <style>
+ #stage div {
+ position: absolute;
+ -webkit-mask-image: url(../resources/star.svg);
+ mask: url(../resources/star.svg#star-mask);
+ }
+ </style>
+</head>
+<body>
+ <div id="stage"></div>
+ <script src="../../resources/strings.js"></script>
+ <script src="../../resources/extensions.js"></script>
+ <script src="../../resources/statistics.js"></script>
+ <script src="../resources/math.js"></script>
+ <script src="../resources/main.js"></script>
+ <script src="../master/resources/particles.js"></script>
+ <script src="resources/dom-particles.js"></script>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/compositing-transforms.js b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/compositing-transforms.js
new file mode 100644
index 0000000000..9fd401eeeb
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/compositing-transforms.js
@@ -0,0 +1,66 @@
+(function() {
+
+BouncingCompositedImage = Utilities.createSubclass(BouncingParticle,
+ function(stage)
+ {
+ BouncingParticle.call(this, stage);
+
+ this.element = document.createElement("img");
+ this.element.style.width = this.size.x + "px";
+ this.element.style.height = this.size.y + "px";
+ this.element.setAttribute("src", stage.imageSrc);
+
+ if (stage.useFilters)
+ this.element.style.filter = "hue-rotate(" + Stage.randomAngle() + "rad)";
+
+ stage.element.appendChild(this.element);
+ this._move();
+ }, {
+
+ _move: function()
+ {
+ this.element.style.transform = "translate3d(" + this.position.x + "px," + this.position.y + "px, 0) " + this.rotater.rotateZ();
+ },
+
+ animate: function(timeDelta)
+ {
+ BouncingParticle.prototype.animate.call(this, timeDelta);
+ this._move();
+ }
+});
+
+CompositingTransformsStage = Utilities.createSubclass(BouncingParticlesStage,
+ function()
+ {
+ BouncingParticlesStage.call(this);
+ }, {
+
+ initialize: function(benchmark, options)
+ {
+ BouncingParticlesStage.prototype.initialize.call(this, benchmark, options);
+
+ this.imageSrc = options["imageSrc"] || "../resources/yin-yang.svg";
+ this.useFilters = options["filters"] == "yes";
+ },
+
+ createParticle: function()
+ {
+ return new BouncingCompositedImage(this);
+ },
+
+ particleWillBeRemoved: function(particle)
+ {
+ particle.element.remove();
+ }
+});
+
+CompositedTransformsBenchmark = Utilities.createSubclass(Benchmark,
+ function(options)
+ {
+ Benchmark.call(this, new CompositingTransformsStage(), options);
+ }
+);
+
+window.benchmarkClass = CompositedTransformsBenchmark;
+
+})();
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/dom-particles.js b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/dom-particles.js
new file mode 100644
index 0000000000..471444b2e7
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/dom-particles.js
@@ -0,0 +1,73 @@
+(function() {
+
+DOMParticle = Utilities.createSubclass(Particle,
+ function(stage)
+ {
+ this.element = document.createElement("div");
+ stage.element.appendChild(this.element);
+
+ Particle.call(this, stage);
+ }, {
+
+ reset: function()
+ {
+ Particle.prototype.reset.call(this);
+
+ this.position = Stage.randomElementInArray(this.stage.emitLocation);
+
+ var angle = Stage.randomInt(0, this.stage.emitSteps) / this.stage.emitSteps * Math.PI * 2 + Stage.dateCounterValue(100) * this.stage.emissionSpin;
+ this.velocity = new Point(Math.sin(angle), Math.cos(angle))
+ .multiply(Stage.random(.5, 2.5));
+
+ this.element.style.width = this.size.x + "px";
+ this.element.style.height = this.size.y + "px";
+ this.stage.colorOffset = (this.stage.colorOffset + 1) % 360;
+ this.element.style.backgroundColor = "hsl(" + this.stage.colorOffset + ", 70%, 45%)";
+ },
+
+ move: function()
+ {
+ this.element.style.transform = "translate(" + this.position.x + "px, " + this.position.y + "px)" + this.rotater.rotateZ();
+ }
+});
+
+DOMParticleStage = Utilities.createSubclass(ParticlesStage,
+ function()
+ {
+ ParticlesStage.call(this);
+ }, {
+
+ initialize: function(benchmark)
+ {
+ ParticlesStage.prototype.initialize.call(this, benchmark);
+ this.emissionSpin = Stage.random(0, 3);
+ this.emitSteps = Stage.randomInt(4, 6);
+ this.emitLocation = [
+ new Point(this.size.x * .25, this.size.y * .333),
+ new Point(this.size.x * .5, this.size.y * .25),
+ new Point(this.size.x * .75, this.size.y * .333)
+ ];
+ this.colorOffset = Stage.randomInt(0, 359);
+ },
+
+ createParticle: function()
+ {
+ return new DOMParticle(this);
+ },
+
+ willRemoveParticle: function(particle)
+ {
+ particle.element.remove();
+ }
+});
+
+DOMParticleBenchmark = Utilities.createSubclass(Benchmark,
+ function(options)
+ {
+ Benchmark.call(this, new DOMParticleStage(), options);
+ }
+);
+
+window.benchmarkClass = DOMParticleBenchmark;
+
+})();
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/focus.js b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/focus.js
new file mode 100644
index 0000000000..d7722cdff4
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/focus.js
@@ -0,0 +1,166 @@
+(function() {
+
+var maxVerticalOffset = 50;
+var minimumDiameter = 30;
+var centerDiameter = 90;
+var sizeVariance = 60;
+var travelDistance = 50;
+
+var opacityMultiplier = 30;
+
+var FocusElement = Utilities.createClass(
+ function(stage)
+ {
+ var size = minimumDiameter + sizeVariance;
+
+ // Size and blurring are a function of depth.
+ this._depth = Pseudo.random();
+ var distance = Utilities.lerp(this._depth, 0, sizeVariance);
+ size -= distance;
+
+ var top = Stage.random(0, stage.size.height - size) - stage.maxBlurValue * 3;
+ var left = Stage.random(0, stage.size.width - size) - stage.maxBlurValue * 3;
+
+ this.container = document.createElement('div');
+ this.container.style.width = (size + stage.maxBlurValue * 6) + "px";
+ this.container.style.height = (size + stage.maxBlurValue * 6) + "px";
+ this.container.style.top = top + "px";
+ this.container.style.left = left + "px";
+ this.container.style.zIndex = Math.round((1 - this._depth) * 10);
+
+ this.particle = Utilities.createElement("div", {}, this.container);
+ this.particle.style.width = size + "px";
+ this.particle.style.height = size + "px";
+ this.particle.style.top = (stage.maxBlurValue * 3) + "px";
+ this.particle.style.left = (stage.maxBlurValue * 3) + "px";
+
+ var depthMultiplier = Utilities.lerp(1 - this._depth, 0.8, 1);
+ this._sinMultiplier = Pseudo.random() * Stage.randomSign() * depthMultiplier * travelDistance;
+ this._cosMultiplier = Pseudo.random() * Stage.randomSign() * depthMultiplier * travelDistance;
+ }, {
+
+ hide: function()
+ {
+ this.container.style.display = "none";
+ },
+
+ show: function()
+ {
+ this.container.style.display = "block";
+ },
+
+ animate: function(stage, sinFactor, cosFactor)
+ {
+ var top = sinFactor * this._sinMultiplier;
+ var left = cosFactor * this._cosMultiplier;
+
+ Utilities.setElementPrefixedProperty(this.container, "filter", "blur(" + stage.getBlurValue(this._depth) + "px) opacity(" + stage.getOpacityValue(this._depth) + "%)");
+ this.container.style.transform = "translate3d(" + left + "%, " + top + "%, 0)";
+ }
+});
+
+var FocusStage = Utilities.createSubclass(Stage,
+ function()
+ {
+ Stage.call(this);
+ }, {
+
+ movementDuration: 2500,
+ focusDuration: 1000,
+
+ centerObjectDepth: 0.0,
+
+ minBlurValue: 1.5,
+ maxBlurValue: 15,
+ maxCenterObjectBlurValue: 5,
+
+ initialize: function(benchmark, options)
+ {
+ Stage.prototype.initialize.call(this, benchmark, options);
+
+ this._testElements = [];
+ this._focalPoint = 0.5;
+ this._offsetIndex = 0;
+
+ this._centerElement = document.getElementById("center-text");
+ this._centerElement.style.width = (centerDiameter + this.maxCenterObjectBlurValue * 6) + "px";
+ this._centerElement.style.height = (centerDiameter + this.maxCenterObjectBlurValue * 6) + "px";
+ this._centerElement.style.zIndex = Math.round(10 * this.centerObjectDepth);
+
+ var particle = document.querySelector("#center-text div");
+ particle.style.width = centerDiameter + "px";
+ particle.style.height = centerDiameter + "px";
+ particle.style.top = (this.maxCenterObjectBlurValue * 3) + "px";
+ particle.style.left = (this.maxCenterObjectBlurValue * 3) + "px";
+
+ var blur = this.getBlurValue(this.centerObjectDepth, true);
+ Utilities.setElementPrefixedProperty(this._centerElement, "filter", "blur(" + blur + "px)");
+ },
+
+ complexity: function()
+ {
+ return 1 + this._offsetIndex;
+ },
+
+ tune: function(count)
+ {
+ if (count == 0)
+ return;
+
+ if (count < 0) {
+ this._offsetIndex = Math.max(0, this._offsetIndex + count);
+ for (var i = this._offsetIndex; i < this._testElements.length; ++i)
+ this._testElements[i].hide();
+ return;
+ }
+
+ var newIndex = this._offsetIndex + count;
+ for (var i = this._testElements.length; i < newIndex; ++i) {
+ var obj = new FocusElement(this);
+ this._testElements.push(obj);
+ this.element.appendChild(obj.container);
+ }
+ for (var i = this._offsetIndex; i < newIndex; ++i)
+ this._testElements[i].show();
+ this._offsetIndex = newIndex;
+ },
+
+ animate: function()
+ {
+ var time = this._benchmark.timestamp;
+ var sinFactor = Math.sin(time / this.movementDuration);
+ var cosFactor = Math.cos(time / this.movementDuration);
+
+ var focusProgress = 0.5 + 0.5 * Math.sin(time / this.focusDuration);
+ this._focalPoint = focusProgress;
+
+ Utilities.setElementPrefixedProperty(this._centerElement, "filter", "blur(" + this.getBlurValue(this.centerObjectDepth, true) + "px)");
+
+ for (var i = 0; i < this._offsetIndex; ++i)
+ this._testElements[i].animate(this, sinFactor, cosFactor);
+ },
+
+ getBlurValue: function(depth, isCenter)
+ {
+ if (isCenter)
+ return 1 + Math.abs(depth - this._focalPoint) * (this.maxCenterObjectBlurValue - 1);
+
+ return Utilities.lerp(Math.abs(depth - this._focalPoint), this.minBlurValue, this.maxBlurValue);
+ },
+
+ getOpacityValue: function(depth)
+ {
+ return Math.max(1, opacityMultiplier * (1 - Math.abs(depth - this._focalPoint)));
+ },
+});
+
+var FocusBenchmark = Utilities.createSubclass(Benchmark,
+ function(options)
+ {
+ Benchmark.call(this, new FocusStage(), options);
+ }
+);
+
+window.benchmarkClass = FocusBenchmark;
+
+}());
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/leaves.js b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/leaves.js
new file mode 100644
index 0000000000..604c973667
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/leaves.js
@@ -0,0 +1,48 @@
+Leaf = Utilities.createSubclass(Particle,
+ function(stage)
+ {
+ this.element = document.createElement("img");
+ this.element.setAttribute("src", Stage.randomElementInArray(stage.images).src);
+ stage.element.appendChild(this.element);
+
+ Particle.call(this, stage);
+ }, {
+
+ sizeMinimum: 20,
+ sizeRange: 40,
+
+ reset: function()
+ {
+ Particle.prototype.reset.call(this);
+ this.element.style.width = this.size.x + "px";
+ this.element.style.height = this.size.y + "px";
+ this._opacity = .01;
+ this._opacityRate = 0.02 * Stage.random(1, 6);
+ this._position = new Point(Stage.random(0, this.maxPosition.x), Stage.random(-this.size.height, this.maxPosition.y));
+ this._velocity = new Point(Stage.random(-6, -2), .1 * this.size.y + Stage.random(-1, 1));
+ },
+
+ animate: function(timeDelta)
+ {
+ this.rotater.next(timeDelta);
+
+ this._position.x += this._velocity.x + 8 * this.stage.focusX;
+ this._position.y += this._velocity.y;
+ this._opacity += this._opacityRate;
+ if (this._opacity > 1) {
+ this._opacity = 1;
+ this._opacityRate *= -1;
+ } else if (this._opacity < 0 || this._position.y > this.stage.size.height)
+ this.reset();
+
+ if (this._position.x < -this.size.width || this._position.x > this.stage.size.width)
+ this._position.x = this._position.x - Math.sign(this._position.x) * (this.size.width + this.stage.size.width);
+ this.move();
+ },
+
+ move: function()
+ {
+ this.element.style.transform = "translate(" + this._position.x + "px, " + this._position.y + "px)" + this.rotater.rotateZ();
+ this.element.style.opacity = this._opacity;
+ }
+});
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/canvas-stage.html b/third_party/webkit/PerformanceTests/MotionMark/tests/master/canvas-stage.html
new file mode 100644
index 0000000000..f86cb44e10
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/canvas-stage.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="../resources/stage.css">
+</head>
+<body>
+ <canvas id="stage"></canvas>
+ <script src="../../resources/strings.js"></script>
+ <script src="../../resources/extensions.js"></script>
+ <script src="../../resources/statistics.js"></script>
+ <script src="../resources/math.js"></script>
+ <script src="../resources/main.js"></script>
+ <script src="resources/canvas-stage.js"></script>
+ <script src="resources/canvas-tests.js"></script>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/focus.html b/third_party/webkit/PerformanceTests/MotionMark/tests/master/focus.html
new file mode 100644
index 0000000000..e97a7cd79f
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/focus.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="../resources/stage.css">
+ <style type="text/css">
+
+ #stage {
+ background-color: #201A1F;
+ }
+
+ #stage div {
+ position: absolute;
+ background-color: #DEDADD;
+ border-radius: 50%;
+ display: none;
+ }
+ </style>
+</head>
+<body>
+ <div id="stage"></div>
+ <script src="../../resources/strings.js"></script>
+ <script src="../../resources/extensions.js"></script>
+ <script src="../../resources/statistics.js"></script>
+ <script src="../resources/math.js"></script>
+ <script src="../resources/main.js"></script>
+ <script src="resources/focus.js"></script>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/image-data.html b/third_party/webkit/PerformanceTests/MotionMark/tests/master/image-data.html
new file mode 100644
index 0000000000..36b52c9d87
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/image-data.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="../resources/stage.css">
+ <style type="text/css">
+
+ #stage {
+ background-color: #000;
+ }
+
+ #stage canvas {
+ position: absolute;
+ transform: translateZ(0);
+ }
+
+ </style>
+</head>
+<body>
+ <div id="stage"></div>
+ <script src="../../resources/strings.js"></script>
+ <script src="../../resources/extensions.js"></script>
+ <script src="../../resources/statistics.js"></script>
+ <script src="../resources/math.js"></script>
+ <script src="../resources/main.js"></script>
+ <script src="resources/image-data.js"></script>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/leaves.html b/third_party/webkit/PerformanceTests/MotionMark/tests/master/leaves.html
new file mode 100644
index 0000000000..ada054025c
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/leaves.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="../resources/stage.css">
+ <style>
+ #stage {
+ background-color: #23282B;
+ }
+ #stage img {
+ position: absolute;
+ }
+ </style>
+</head>
+<body>
+ <div id="stage"></div>
+ <script src="../../resources/strings.js"></script>
+ <script src="../../resources/extensions.js"></script>
+ <script src="../../resources/statistics.js"></script>
+ <script src="../resources/math.js"></script>
+ <script src="../resources/main.js"></script>
+ <script src="resources/particles.js"></script>
+ <script src="resources/leaves.js"></script>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/multiply.html b/third_party/webkit/PerformanceTests/MotionMark/tests/master/multiply.html
new file mode 100644
index 0000000000..717aff7d8b
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/multiply.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="../resources/stage.css">
+ <style type="text/css">
+
+ #stage {
+ background-color: #000;
+ }
+
+ #stage div {
+ position: absolute;
+ }
+
+ #stage .div-0 {
+ border-top-right-radius: 100%;
+ }
+
+ #stage .div-1 {
+ border-top-left-radius: 100%;
+ }
+
+ #stage .div-2 {
+ border-bottom-left-radius: 100%;
+ }
+
+ #stage .div-3 {
+ border-bottom-right-radius: 100%;
+ }
+
+ #stage .div-4 {
+ border-bottom-left-radius: 100%;
+ border-top-right-radius: 100%;
+ }
+
+ #stage .div-5 {
+ border-bottom-right-radius: 100%;
+ border-top-left-radius: 100%;
+ }
+ </style>
+</head>
+<body>
+ <div id="stage">
+ </div>
+ <script src="../../resources/strings.js"></script>
+ <script src="../../resources/extensions.js"></script>
+ <script src="../../resources/statistics.js"></script>
+ <script src="../resources/math.js"></script>
+ <script src="../resources/main.js"></script>
+ <script src="resources/multiply.js"></script>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/canvas-stage.js b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/canvas-stage.js
new file mode 100644
index 0000000000..22002eccd6
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/canvas-stage.js
@@ -0,0 +1,52 @@
+SimpleCanvasStage = Utilities.createSubclass(Stage,
+ function(canvasObject)
+ {
+ Stage.call(this);
+ this._canvasObject = canvasObject;
+ this.objects = [];
+ this.offsetIndex = 0;
+ }, {
+
+ initialize: function(benchmark, options)
+ {
+ Stage.prototype.initialize.call(this, benchmark, options);
+ this.context = this.element.getContext("2d");
+ },
+
+ tune: function(count)
+ {
+ if (count == 0)
+ return;
+
+ if (count < 0) {
+ this.offsetIndex = Math.min(this.offsetIndex - count, this.objects.length);
+ return;
+ }
+
+ var newIndex = this.offsetIndex - count;
+ if (newIndex < 0) {
+ this.offsetIndex = 0;
+ newIndex = -newIndex;
+ for (var i = 0; i < newIndex; ++i) {
+ if (this._canvasObject.constructor === Array)
+ this.objects.push(new (Stage.randomElementInArray(this._canvasObject))(this));
+ else
+ this.objects.push(new this._canvasObject(this));
+ }
+ } else
+ this.offsetIndex = newIndex;
+ },
+
+ animate: function()
+ {
+ var context = this.context;
+ context.clearRect(0, 0, this.size.x, this.size.y);
+ for (var i = this.offsetIndex, length = this.objects.length; i < length; ++i)
+ this.objects[i].draw(context);
+ },
+
+ complexity: function()
+ {
+ return this.objects.length - this.offsetIndex;
+ }
+});
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/canvas-tests.js b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/canvas-tests.js
new file mode 100644
index 0000000000..79fc867082
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/canvas-tests.js
@@ -0,0 +1,311 @@
+(function() {
+
+// === PAINT OBJECTS ===
+
+CanvasLineSegment = Utilities.createClass(
+ function(stage)
+ {
+ var circle = Stage.randomInt(0, 3);
+ this._color = ["#e01040", "#10c030", "#744CBA", "#e05010"][circle];
+ this._lineWidth = Math.pow(Pseudo.random(), 12) * 20 + 3;
+ this._omega = Pseudo.random() * 3 + 0.2;
+ var theta = Stage.randomAngle();
+ this._cosTheta = Math.cos(theta);
+ this._sinTheta = Math.sin(theta);
+ this._startX = stage.circleRadius * this._cosTheta + stage.circleX[circle];
+ this._startY = stage.circleRadius * this._sinTheta + stage.circleY[circle];
+ this._length = Math.pow(Pseudo.random(), 8) * stage.lineLengthMaximum + stage.lineMinimum;
+ this._segmentDirection = Pseudo.random() > 0.5 ? -1 : 1;
+ }, {
+
+ draw: function(context)
+ {
+ context.strokeStyle = this._color;
+ context.lineWidth = this._lineWidth;
+
+ this._length += Math.sin(Stage.dateCounterValue(100) * this._omega);
+
+ 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();
+ }
+});
+
+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));
+
+ this._point = new Point(distanceX * (randX + (randY % 2) / 2), distanceY * (randY + .5));
+
+ this._radius = 20 + Math.pow(Pseudo.random(), 5) * (Math.min(distanceX, distanceY) / 1.8);
+ this._startAngle = Stage.randomAngle();
+ this._endAngle = Stage.randomAngle();
+ this._omega = (Pseudo.random() - 0.5) * 0.3;
+ this._counterclockwise = Stage.randomBool();
+ var colors = ["#101010", "#808080", "#c0c0c0"];
+ colors.push(["#e01040", "#10c030", "#e05010"][(randX + Math.ceil(randY / 2)) % 3]);
+ this._color = colors[Math.floor(Pseudo.random() * colors.length)];
+ this._lineWidth = 1 + Math.pow(Pseudo.random(), 5) * 30;
+ this._doStroke = Stage.randomInt(0, 3) != 0;
+ }, {
+
+ draw: function(context)
+ {
+ this._startAngle += this._omega;
+ this._endAngle += this._omega / 2;
+
+ 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();
+ }
+ }
+});
+
+// CanvasLinePoint contains no draw() method since it is either moveTo or
+// lineTo depending on its index.
+CanvasLinePoint = Utilities.createClass(
+ function(stage)
+ {
+ var colors = ["#101010", "#808080", "#c0c0c0", "#101010", "#808080", "#c0c0c0", "#e01040"];
+ this.color = Stage.randomElementInArray(colors);
+ this.width = Math.pow(Pseudo.random(), 5) * 20 + 1;
+ this.isSplit = Pseudo.random() > 0.95;
+
+ var nextPoint;
+ if (stage.objects.length)
+ nextPoint = this.randomPoint(stage, stage.objects[stage.objects.length - 1].coordinate);
+ else
+ nextPoint = this.randomPoint(stage, this.gridSize.center);
+ this.point = nextPoint.point;
+ this.coordinate = nextPoint.coordinate;
+ }, {
+
+ gridSize: new Point(80, 40),
+ offsets: [
+ new Point(-4, 0),
+ new Point(2, 0),
+ new Point(1, -2),
+ new Point(1, 2),
+ ],
+
+ randomPoint: function(stage, startCoordinate)
+ {
+ var coordinate = startCoordinate;
+ if (stage.objects.length) {
+ var offset = Stage.randomElementInArray(this.offsets);
+
+ coordinate = coordinate.add(offset);
+ if (coordinate.x < 0 || coordinate.x > this.gridSize.width)
+ coordinate.x -= offset.x * 2;
+ if (coordinate.y < 0 || coordinate.y > this.gridSize.height)
+ coordinate.y -= offset.y * 2;
+ }
+
+ var x = (coordinate.x + .5) * stage.size.x / (this.gridSize.width + 1);
+ var y = (coordinate.y + .5) * stage.size.y / (this.gridSize.height + 1);
+ return {
+ point: new Point(x, y),
+ coordinate: coordinate
+ };
+ },
+
+ draw: function(context)
+ {
+ context.lineTo(this.point.x, this.point.y);
+ }
+});
+
+CanvasQuadraticSegment = Utilities.createSubclass(CanvasLinePoint,
+ function(stage)
+ {
+ CanvasLinePoint.call(this, stage);
+ // The chosen point is instead the control point.
+ this._point2 = this.point;
+
+ // Get another random point for the actual end point of the segment.
+ var nextPoint = this.randomPoint(stage, this.coordinate);
+ this.point = nextPoint.point;
+ this.coordinate = nextPoint.coordinate;
+ }, {
+
+ draw: function(context)
+ {
+ context.quadraticCurveTo(this._point2.x, this._point2.y, this.point.x, this.point.y);
+ }
+});
+
+CanvasBezierSegment = Utilities.createSubclass(CanvasLinePoint,
+ function(stage)
+ {
+ CanvasLinePoint.call(this, stage);
+ // The chosen point is instead the first control point.
+ this._point2 = this.point;
+ var nextPoint = this.randomPoint(stage, this.coordinate);
+ this._point3 = nextPoint.point;
+
+ nextPoint = this.randomPoint(stage, nextPoint.coordinate);
+ this.point = nextPoint.point;
+ this.coordinate = nextPoint.coordinate;
+ }, {
+
+ draw: function(context, off)
+ {
+ context.bezierCurveTo(this._point2.x, this._point2.y, this._point3.x, this._point3.y, this.point.x, this.point.y);
+ }
+});
+
+// === STAGES ===
+
+CanvasLineSegmentStage = Utilities.createSubclass(SimpleCanvasStage,
+ function()
+ {
+ SimpleCanvasStage.call(this, CanvasLineSegment);
+ }, {
+
+ initialize: function(benchmark, options)
+ {
+ SimpleCanvasStage.prototype.initialize.call(this, benchmark, options);
+ this.context.lineCap = options["lineCap"] || "butt";
+ this.lineMinimum = 20;
+ this.lineLengthMaximum = 40;
+ this.circleRadius = this.size.x / 8 - .4 * (this.lineMinimum + this.lineLengthMaximum);
+ this.circleX = [
+ 5.5 / 32 * this.size.x,
+ 12.5 / 32 * this.size.x,
+ 19.5 / 32 * this.size.x,
+ 26.5 / 32 * this.size.x,
+ ];
+ this.circleY = [
+ 2.1 / 3 * this.size.y,
+ 0.9 / 3 * this.size.y,
+ 2.1 / 3 * this.size.y,
+ 0.9 / 3 * this.size.y
+ ];
+ this.halfSize = this.size.multiply(.5);
+ this.twoFifthsSizeX = this.size.x * .4;
+ },
+
+ animate: function()
+ {
+ var context = this.context;
+ context.clearRect(0, 0, this.size.x, this.size.y);
+
+ var angle = Stage.dateFractionalValue(3000) * Math.PI * 2;
+ var dx = this.twoFifthsSizeX * Math.cos(angle);
+ var dy = this.twoFifthsSizeX * Math.sin(angle);
+
+ var gradient = context.createLinearGradient(this.halfSize.x + dx, this.halfSize.y + dy, this.halfSize.x - dx, this.halfSize.y - dy);
+ var gradientStep = 0.5 + 0.5 * Math.sin(Stage.dateFractionalValue(5000) * Math.PI * 2);
+ var colorStopStep = Utilities.lerp(gradientStep, -.1, .1);
+ var brightnessStep = Math.round(Utilities.lerp(gradientStep, 32, 64));
+ var color1Step = "rgba(" + brightnessStep + "," + brightnessStep + "," + (brightnessStep << 1) + ",.4)";
+ var color2Step = "rgba(" + (brightnessStep << 1) + "," + (brightnessStep << 1) + "," + brightnessStep + ",.4)";
+ gradient.addColorStop(0, color1Step);
+ gradient.addColorStop(.2 + colorStopStep, color1Step);
+ gradient.addColorStop(.8 - colorStopStep, color2Step);
+ gradient.addColorStop(1, color2Step);
+
+ context.lineWidth = 15;
+ for(var i = 0; i < 4; i++) {
+ context.strokeStyle = ["#e01040", "#10c030", "#744CBA", "#e05010"][i];
+ context.fillStyle = ["#70051d", "#016112", "#2F0C6E", "#702701"][i];
+ context.beginPath();
+ context.arc(this.circleX[i], this.circleY[i], this.circleRadius, 0, Math.PI*2);
+ context.stroke();
+ context.fill();
+ context.fillStyle = gradient;
+ context.fill();
+ }
+
+ for (var i = this.offsetIndex, length = this.objects.length; i < length; ++i)
+ this.objects[i].draw(context);
+ }
+});
+
+CanvasLinePathStage = Utilities.createSubclass(SimpleCanvasStage,
+ function()
+ {
+ SimpleCanvasStage.call(this, [CanvasLinePoint, CanvasLinePoint, CanvasQuadraticSegment, CanvasBezierSegment]);
+ }, {
+
+ initialize: function(benchmark, options)
+ {
+ SimpleCanvasStage.prototype.initialize.call(this, benchmark, options);
+ this.context.lineJoin = options["lineJoin"] || "bevel";
+ this.context.lineCap = options["lineCap"] || "butt";
+ },
+
+ animate: function() {
+ var context = this.context;
+
+ context.clearRect(0, 0, this.size.x, this.size.y);
+ context.beginPath();
+ for (var i = this.offsetIndex, length = this.objects.length; i < length; ++i) {
+ var object = this.objects[i];
+ if (i == this.offsetIndex) {
+ context.lineWidth = object.width;
+ context.strokeStyle = object.color;
+ context.beginPath();
+ context.moveTo(object.point.x, object.point.y);
+ } else {
+ object.draw(context);
+
+ if (object.isSplit) {
+ context.stroke();
+
+ context.lineWidth = object.width;
+ context.strokeStyle = object.color;
+ context.beginPath();
+ context.moveTo(object.point.x, object.point.y);
+ }
+
+ if (Pseudo.random() > 0.995)
+ object.isSplit = !object.isSplit;
+ }
+ }
+ context.stroke();
+ }
+});
+
+// === BENCHMARK ===
+
+CanvasPathBenchmark = Utilities.createSubclass(Benchmark,
+ function(options)
+ {
+ var stage;
+ switch (options["pathType"]) {
+ case "line":
+ stage = new CanvasLineSegmentStage();
+ break;
+ case "linePath":
+ stage = new CanvasLinePathStage();
+ break;
+ case "arcs":
+ stage = new SimpleCanvasStage(CanvasArc);
+ break;
+ }
+
+ Benchmark.call(this, stage, options);
+ }
+);
+
+window.benchmarkClass = CanvasPathBenchmark;
+
+})(); \ No newline at end of file
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/compass.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/compass.svg
new file mode 100644
index 0000000000..3f94e7a4b2
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/compass.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright © 2016 Apple Inc. All rights reserved. -->
+<svg width="48px" height="48px" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <path d="M 24 45.7600002 L 24 45.7600002 C 36.0177159 45.7600002 45.7599999 36.0177161 45.7599999 24.0000001 C 45.7599999 11.9822838 36.0177159 2.24000001 24 2.24000001 C 11.9822838 2.24000001 2.23999999 11.9822838 2.23999999 24.0000001 C 2.23999999 36.0177161 11.9822838 45.7600002 24 45.7600002 L 24 45.7600002 L 24 45.7600002 L 24 45.7600002 Z M 24 48 L 24 48 C 10.745166 48 8.52651283e-14 37.254834 8.52651283e-14 24.0000001 C 8.52651283e-14 10.745166 10.745166 0 24 0 C 37.254834 0 48 10.745166 48 24.0000001 C 48 37.254834 37.254834 48 24 48 L 24 48 L 24 48 L 24 48 Z" fill="rgb(142, 142, 147)"/>
+ <path fill="white" d="M 19.2141787 30.7527044 C 20.0566026 31.3582067 21.0164459 31.8087988 22.052466 32.0629879 L 24.0150243 38.3621108 L 25.9644157 32.0671275 C 28.9532689 31.3397602 31.304042 28.97474 32.0270276 25.9677724 L 38.2840894 24.0065666 L 32.38318 22.1457238 L 30.1049072 24.2136546 C 29.9995478 27.5073249 27.2907334 30.1510903 24.0134391 30.1359337 C 23.1661809 30.1431339 22.3840431 29.959524 21.6645278 29.6641888 L 19.2141787 30.7527044 L 19.2141787 30.7527044 L 19.2141787 30.7527044 Z M 28.8019182 17.2563866 C 27.4120183 16.2548466 25.9438825 15.9331447 25.9438825 15.9331447 L 23.9849759 9.63788916 L 22.0355845 15.9328727 C 19.0467312 16.6602398 16.695958 19.0252601 15.9729726 22.0322277 L 9.71591065 23.9934336 C 9.71591065 23.9934336 13.7573684 25.2679011 15.7780972 25.9051349 L 17.8923556 23.9486543 C 17.9116726 20.5783691 20.6200789 17.8803136 23.9912031 17.8674375 C 24.8266313 17.8130168 26.1806153 18.2277657 26.3381938 18.3358993 C 26.3381937 18.3358993 28.8019182 17.2563866 28.8019182 17.2563866 L 28.8019182 17.2563866 L 28.8019182 17.2563866 Z"/>
+ <path fill="white" d="M 22.4528571 21.5612813 L 10.1267612 32.8610634 L 25.4820204 26.3285511 L 37.8732388 15.1389366 L 22.4528571 21.5612813 L 22.4528571 21.5612813 L 22.4528571 21.5612813 Z"/>
+</svg>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/compass100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/compass100.png
new file mode 100644
index 0000000000..e513ce11e3
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/compass100.png
Binary files differ
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/console.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/console.svg
new file mode 100644
index 0000000000..e3c7611d2a
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/console.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright © 2016 Apple Inc. All rights reserved. -->
+<svg width="48px" height="48px" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect stroke="rgb(0, 136, 204)" stroke-width="2.5" x="5.03735352" y="5.03735352" width="37.925293" height="37.925293" rx="4" fill="none"/>
+ <path d="M 13.164202 13.164202 L 24 24 L 13.164202 34.835798 M 24 14 L 35 14 M 29.5 24 L 34.9999999 24 M 24 34 L 35 34" stroke="white" stroke-width="2.5" fill="none" />
+</svg>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/console100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/console100.png
new file mode 100644
index 0000000000..81f9c1641d
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/console100.png
Binary files differ
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/contribute.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/contribute.svg
new file mode 100644
index 0000000000..68860efa86
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/contribute.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright © 2016 Apple Inc. All rights reserved. -->
+<svg width="48px" height="48px" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <path fill="rgb(203, 170, 68)" d="M 24 45.76 L 24 45.76 C 36.0177161 45.76 45.76 36.0177162 45.76 24 C 45.76 11.9822838 36.0177161 2.24 24 2.24 C 11.9822838 2.24 2.24 11.9822838 2.24 24 C 2.24 36.0177162 11.9822838 45.76 24 45.76 L 24 45.76 L 24 45.76 L 24 45.76 Z M 24 48 L 24 48 C 10.745166 48 -1.77635684e-14 37.254834 -1.77635684e-14 24 C -1.77635684e-14 10.745166 10.745166 2.84217094e-14 24 2.84217094e-14 C 37.254834 2.84217094e-14 48 10.745166 48 24 C 48 37.254834 37.254834 48 24 48 L 24 48 L 24 48 L 24 48 Z"/>
+ <path d="M 29.4897098 23.3065925 L 26.2706917 20.9393745 L 26.6482584 24.3031351 L 28.4802897 29.4247528 L 29.4897098 33.8205977 L 30.4989581 29.4247528 L 32.3309894 24.3031351 L 32.7087278 20.9393745 L 29.4897098 23.3065925 Z M 18.8503641 23.3065925 L 15.631346 20.9393745 L 16.0090845 24.3031351 L 17.8411157 29.4247528 L 18.8503641 33.8205977 L 19.8597841 29.4247528 L 21.6916437 24.3031351 L 22.0693821 20.9393745 L 18.8503641 23.3065925 Z M 37.2876041 24.3031351 L 39.1196354 29.4247528 L 40.3400738 34.740219 L 38.3454433 35 L 36.6368638 29.562799 C 36.6368638 29.562799 34.8092967 25.6310573 34.8092967 25.4866582 C 34.8092967 25.6310573 32.9819013 29.562799 32.9819013 29.562799 L 31.2733218 35 L 29.4897098 34.7676909 L 27.7060977 35 L 25.9975182 29.562799 C 25.9975182 29.562799 24.1701228 25.6310573 24.1701228 25.4866582 C 24.1701228 25.6310573 22.3425557 29.562799 22.3425557 29.562799 L 20.6339762 35 L 18.8503641 34.7676909 L 17.066752 35 L 15.3581725 29.562799 C 15.3581725 29.562799 13.5307771 25.6310573 13.5307771 25.4866582 C 13.5307771 25.6310573 11.7033817 29.562799 11.7033817 29.562799 L 9.9946305 35 L 8 34.740219 L 9.22043846 29.4247528 L 11.0524697 24.3031351 L 11.4302081 20.9393745 L 8.21101841 23.3065925 L 8.21101841 21.228001 L 11.6719607 18.326455 L 12.3810787 18.2218901 L 12.3810787 17.9233051 C 11.4619725 17.51054 10.825655 16.6183906 10.825655 15.5839024 C 10.825655 14.156738 12.0368217 13 13.5307771 13 C 15.0247325 13 16.2358992 14.156738 16.2358992 15.5839024 C 16.2358992 16.6183906 15.5995817 17.51054 14.6804755 17.9233051 L 14.6804755 18.2218901 L 15.3895935 18.326455 L 18.8503641 21.228001 L 22.3113064 18.326455 L 23.0204244 18.2218901 L 23.0204244 17.9233051 C 22.1013182 17.51054 21.4650007 16.6183906 21.4650007 15.5839024 C 21.4650007 14.156738 22.6761674 13 24.1701228 13 C 25.6640782 13 26.8750732 14.156738 26.8750732 15.5839024 C 26.8750732 16.6183906 26.2387556 17.51054 25.3198211 17.9233051 L 25.3198211 18.2218901 L 26.0289391 18.326455 L 29.4897098 21.228001 L 32.9504804 18.326455 L 33.6595984 18.2218901 L 33.6595984 17.9233051 C 32.7406639 17.51054 32.1043463 16.6183906 32.1043463 15.5839024 C 32.1043463 14.156738 33.3153413 13 34.8092967 13 C 36.3034238 13 37.5142471 14.156738 37.5144188 15.5839024 C 37.5144188 16.6183906 36.8781013 17.51054 35.9591668 17.9233051 L 35.9591668 18.2218901 L 36.6682848 18.326455 L 40.1290554 21.228001 L 40.1290554 23.3065925 L 36.9100374 20.9393745 L 37.2876041 24.3031351 Z" fill="white"/>
+</svg>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/contribute100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/contribute100.png
new file mode 100644
index 0000000000..790e3dcfca
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/contribute100.png
Binary files differ
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/debugger.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/debugger.svg
new file mode 100644
index 0000000000..646ddf446c
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/debugger.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright © 2016 Apple Inc. All rights reserved. -->
+<svg width="48px" height="48px" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <path d="M 24.1320008 44.328125 C 32.1512251 44.328125 38.6520901 35.226914 38.6520901 24 C 38.6520901 12.773086 32.1512251 3.671875 24.1320008 3.671875 C 16.1127765 3.671875 9.61191153 12.773086 9.61191153 24 C 9.61191153 35.226914 16.1127765 44.328125 24.1320008 44.328125 Z M 13.7861328 10.5 L 34.4768075 10.5 L 13.7861328 10.5 Z M 24.25 11 L 24.25 44.328125 M 34.1640625 37.0680804 L 39.9720982 42.8761161 M 38.5200893 22.25 L 44.328125 22.25 M 9.47991071 22.25 L 3.671875 22.25 M 13.8359375 10.9319196 L 8.02790179 5.12388393 M 34.1640625 10.9319196 L 39.9720982 5.12388393 M 13.972 37.068 L 8.164 42.876" fill="none" stroke="rgb(0, 136, 204)" stroke-width="2.5"/>
+</svg>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/debugger100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/debugger100.png
new file mode 100644
index 0000000000..e2652096dc
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/debugger100.png
Binary files differ
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/focus.js b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/focus.js
new file mode 100644
index 0000000000..04842e744e
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/focus.js
@@ -0,0 +1,129 @@
+(function() {
+
+var minimumDiameter = 30;
+var sizeVariance = 20;
+var travelDistance = 50;
+
+var minBlurValue = 1;
+var maxBlurValue = 10;
+
+var opacityMultiplier = 30;
+var focusDuration = 1000;
+var movementDuration = 2500;
+
+var FocusElement = Utilities.createClass(
+ function(stage)
+ {
+ var size = minimumDiameter + sizeVariance;
+
+ // Size and blurring are a function of depth.
+ this._depth = Pseudo.random();
+ var distance = Utilities.lerp(this._depth, 0, sizeVariance);
+ size -= distance;
+
+ var top = Stage.random(0, stage.size.height - size);
+ var left = Stage.random(0, stage.size.width - size);
+
+ this.particle = document.createElement("div");
+ this.particle.style.width = size + "px";
+ this.particle.style.height = size + "px";
+ this.particle.style.top = top + "px";
+ this.particle.style.left = left + "px";
+ this.particle.style.zIndex = Math.round((1 - this._depth) * 10);
+
+ var depthMultiplier = Utilities.lerp(1 - this._depth, 0.8, 1);
+ this._sinMultiplier = Pseudo.random() * Stage.randomSign() * depthMultiplier * travelDistance;
+ this._cosMultiplier = Pseudo.random() * Stage.randomSign() * depthMultiplier * travelDistance;
+
+ this.animate(stage, 0, 0);
+ }, {
+
+ hide: function()
+ {
+ this.particle.style.display = "none";
+ },
+
+ show: function()
+ {
+ this.particle.style.display = "block";
+ },
+
+ animate: function(stage, sinFactor, cosFactor)
+ {
+ var top = sinFactor * this._sinMultiplier;
+ var left = cosFactor * this._cosMultiplier;
+ var distance = Math.abs(this._depth - stage.focalPoint);
+ var blur = Utilities.lerp(distance, minBlurValue, maxBlurValue);
+ var opacity = Math.max(5, opacityMultiplier * (1 - distance));
+
+ Utilities.setElementPrefixedProperty(this.particle, "filter", "blur(" + blur + "px) opacity(" + opacity + "%)");
+ this.particle.style.transform = "translate3d(" + left + "%, " + top + "%, 0)";
+ }
+});
+
+var FocusStage = Utilities.createSubclass(Stage,
+ function()
+ {
+ Stage.call(this);
+ }, {
+
+ initialize: function(benchmark, options)
+ {
+ Stage.prototype.initialize.call(this, benchmark, options);
+
+ this._testElements = [];
+ this._offsetIndex = 0;
+ this.focalPoint = 0.5;
+ },
+
+ complexity: function()
+ {
+ return this._offsetIndex;
+ },
+
+ tune: function(count)
+ {
+ if (count == 0)
+ return;
+
+ if (count < 0) {
+ this._offsetIndex = Math.max(0, this._offsetIndex + count);
+ for (var i = this._offsetIndex; i < this._testElements.length; ++i)
+ this._testElements[i].hide();
+ return;
+ }
+
+ var newIndex = this._offsetIndex + count;
+ for (var i = this._testElements.length; i < newIndex; ++i) {
+ var obj = new FocusElement(this);
+ this._testElements.push(obj);
+ this.element.appendChild(obj.particle);
+ }
+ for (var i = this._offsetIndex; i < newIndex; ++i)
+ this._testElements[i].show();
+ this._offsetIndex = newIndex;
+ },
+
+ animate: function()
+ {
+ var time = this._benchmark.timestamp;
+ var sinFactor = Math.sin(time / movementDuration);
+ var cosFactor = Math.cos(time / movementDuration);
+
+ this.focalPoint = 0.5 + 0.5 * Math.sin(time / focusDuration);
+
+ for (var i = 0; i < this._offsetIndex; ++i)
+ this._testElements[i].animate(this, sinFactor, cosFactor);
+ }
+});
+
+var FocusBenchmark = Utilities.createSubclass(Benchmark,
+ function(options)
+ {
+ Benchmark.call(this, new FocusStage(), options);
+ }
+);
+
+window.benchmarkClass = FocusBenchmark;
+
+}());
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/image-data.js b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/image-data.js
new file mode 100644
index 0000000000..6de5d068bb
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/image-data.js
@@ -0,0 +1,181 @@
+(function() {
+
+var ImageDataStage = Utilities.createSubclass(Stage,
+ function() {
+ Stage.call(this);
+
+ this.testElements = [];
+ this._offsetIndex = 0;
+ }, {
+
+ imageWidth: 50,
+ imageHeight: 50,
+ pixelStride: 4,
+ rowStride: 200,
+ weightNegativeThreshold: 0.04,
+ weightPositiveThreshold: 0.96,
+ imageSrcs: [
+ "compass",
+ "console",
+ "contribute",
+ "debugger",
+ "inspector",
+ "layout",
+ "performance",
+ "script",
+ "shortcuts",
+ "standards",
+ "storage",
+ "styles",
+ "timeline"
+ ],
+ images: [],
+
+ initialize: function(benchmark)
+ {
+ Stage.prototype.initialize.call(this, benchmark);
+
+ var lastPromise;
+ var images = this.images;
+ this.imageSrcs.forEach(function(imageSrc) {
+ var promise = this._loadImage("resources/" + imageSrc + ".svg");
+ if (!lastPromise)
+ lastPromise = promise;
+ else {
+ lastPromise = lastPromise.then(function(img) {
+ images.push(img);
+ return promise;
+ });
+ }
+ }, this);
+
+ lastPromise.then(function(img) {
+ images.push(img);
+ benchmark.readyPromise.resolve();
+ }.bind(this));
+ },
+
+ _loadImage: function(src) {
+ var img = new Image;
+ var promise = new SimplePromise;
+
+ img.addEventListener('load', function onImageLoad(e) {
+ img.removeEventListener('load', onImageLoad);
+ promise.resolve(img);
+ });
+
+ img.src = src;
+ return promise;
+ },
+
+ tune: function(count)
+ {
+ if (count == 0)
+ return;
+
+ if (count < 0) {
+ this._offsetIndex = Math.max(this._offsetIndex + count, 0);
+ for (var i = this._offsetIndex; i < this.testElements.length; ++i)
+ this.testElements[i].style.display = "none";
+ return;
+ }
+
+ this._offsetIndex = this._offsetIndex + count;
+ var index = Math.min(this._offsetIndex, this.testElements.length);
+ for (var i = 0; i < index; ++i) {
+ this.testElements[i].style.display = "block";
+ this._refreshElement(this.testElements[i]);
+ }
+ if (this._offsetIndex <= this.testElements.length)
+ return;
+
+ index = this._offsetIndex - this.testElements.length;
+ for (var i = 0; i < index; ++i) {
+ var element = this._createTestElement();
+ this.testElements.push(element);
+ this.element.appendChild(element);
+ }
+ },
+
+ _createTestElement: function() {
+ var element = document.createElement('canvas');
+ element.width = this.imageWidth;
+ element.height = this.imageHeight;
+ element.style.width = this.imageWidth + 'px';
+ element.style.height = this.imageHeight + 'px';
+
+ this._refreshElement(element);
+ return element;
+ },
+
+ _refreshElement: function(element) {
+ var top = Stage.randomInt(0, Math.floor((this.size.height - this.imageHeight) / this.imageHeight)) * this.imageHeight;
+ var left = Stage.randomInt(0, Math.floor((this.size.width - this.imageWidth) / this.imageWidth)) * this.imageWidth;
+
+ element.style.top = top + 'px';
+ element.style.left = left + 'px';
+ },
+
+ animate: function(timeDelta) {
+ for (var i = 0; i < this._offsetIndex; ++i) {
+ var element = this.testElements[i];
+ var context = element.getContext("2d");
+
+ // Get image data
+ var imageData = context.getImageData(0, 0, this.imageWidth, this.imageHeight);
+
+ var didDraw = false,
+ neighborPixelIndex,
+ dataLen = imageData.data.length;
+ for (var j = 0; j < dataLen; j += this.pixelStride) {
+ if (imageData.data[j + 3] === 0)
+ continue;
+
+ // get random neighboring pixel color
+ neighborPixelIndex = this._getRandomNeighboringPixelIndex(j, dataLen);
+
+ // Update the RGB data
+ imageData.data[j] = imageData.data[neighborPixelIndex];
+ imageData.data[j + 1] = imageData.data[neighborPixelIndex + 1];
+ imageData.data[j + 2] = imageData.data[neighborPixelIndex + 2];
+ imageData.data[j + 3] = imageData.data[neighborPixelIndex + 3];
+ didDraw = true;
+ }
+
+ if (didDraw)
+ context.putImageData(imageData, 0, 0);
+ else {
+ this._refreshElement(element);
+ element.getContext("2d").drawImage(Stage.randomElementInArray(this.images), 0, 0, this.imageWidth, this.imageHeight);
+ }
+ }
+ },
+
+ _getRandomNeighboringPixelIndex: function(pixelIdx, pixelArrayLength)
+ {
+ var xOffset = Math.floor((Pseudo.random() - this.weightNegativeThreshold) / (this.weightPositiveThreshold - this.weightNegativeThreshold));
+ var yOffset = Math.floor((Pseudo.random() - this.weightNegativeThreshold) / (this.weightPositiveThreshold - this.weightNegativeThreshold));
+ return (pixelIdx + this.pixelStride * xOffset + this.rowStride * yOffset) % pixelArrayLength;
+ },
+
+ complexity: function()
+ {
+ return this._offsetIndex;
+ }
+});
+
+var ImageDataBenchmark = Utilities.createSubclass(Benchmark,
+ function(options)
+ {
+ Benchmark.call(this, new ImageDataStage(), options);
+ }, {
+
+ waitUntilReady: function() {
+ this.readyPromise = new SimplePromise;
+ return this.readyPromise;
+ }
+});
+
+window.benchmarkClass = ImageDataBenchmark;
+
+}());
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/inspector.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/inspector.svg
new file mode 100644
index 0000000000..68cc413052
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/inspector.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright © 2016 Apple Inc. All rights reserved. -->
+<svg width="48px" height="48px" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <circle fill="none" stroke="rgb(0, 136, 204)" stroke-width="2.5" cx="24" cy="24" r="18"/>
+ <path d="M 28.5 25.5 L 48 25.5 L 48 23 L 28.5 23 L 28.5 25.5 M 23 28.5 L 23 48 L 25.5 48 L 25.5 28.5 L 23 28.5 M 0 25.5 L 19.5 25.5 L 19.5 23 L 5.99520433e-15 23 L 0 25.5 M 23 0 L 23 19.5 L 25.5 19.5 L 25.5 0 L 23 0" fill="white"/>
+</svg>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/inspector100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/inspector100.png
new file mode 100644
index 0000000000..26d1a7d592
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/inspector100.png
Binary files differ
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/layout.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/layout.svg
new file mode 100644
index 0000000000..73db97eb46
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/layout.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright © 2016 Apple Inc. All rights reserved. -->
+<svg width="48px" height="48px" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <path d="M 44.5086986 24.2230775 L 24.1090229 24.2230775 L 24.1090229 4.50363839 L 24.1090229 4.50363839" fill="none" stroke="white" stroke-width="2.5"/>
+ <rect x="3.71000004" y="4.50363839" width="40.7993514" height="39.4388783" fill="none" stroke="rgb(191, 109, 113)" stroke-width="2.5"/>
+</svg>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/layout100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/layout100.png
new file mode 100644
index 0000000000..5b1ec2806b
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/layout100.png
Binary files differ
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/leaves.js b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/leaves.js
new file mode 100644
index 0000000000..7a049836ff
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/leaves.js
@@ -0,0 +1,135 @@
+Leaf = Utilities.createSubclass(Particle,
+ function(stage)
+ {
+ this.element = document.createElement("img");
+ this.element.setAttribute("src", Stage.randomElementInArray(stage.images).src);
+ var sizeString = this.sizeMinimum + "px";
+ this.element.style.width = sizeString;
+ this.element.style.height = sizeString;
+ stage.element.appendChild(this.element);
+
+ Particle.call(this, stage);
+ }, {
+
+ sizeMinimum: 25,
+ sizeRange: 0,
+
+ reset: function()
+ {
+ Particle.prototype.reset.call(this);
+ this._life = Stage.randomInt(20, 100);
+ this._position = new Point(Stage.random(0, this.maxPosition.x), Stage.random(-this.size.height, this.maxPosition.y));
+ this._velocity = new Point(Stage.random(-6, -2), .1 * this.size.y + Stage.random(-1, 1));
+ },
+
+ animate: function(timeDelta)
+ {
+ this.rotater.next(timeDelta);
+
+ this._position.x += this._velocity.x + 8 * this.stage.focusX;
+ this._position.y += this._velocity.y;
+
+ this._life--;
+ if (!this._life || this._position.y > this.stage.size.height)
+ this.reset();
+
+ if (this._position.x < -this.size.width || this._position.x > this.stage.size.width)
+ this._position.x = this._position.x - Math.sign(this._position.x) * (this.size.width + this.stage.size.width);
+ this.move();
+ },
+
+ move: function()
+ {
+ this.element.style.transform = "translate(" + this._position.x + "px, " + this._position.y + "px)" + this.rotater.rotateZ();
+ }
+});
+
+Utilities.extendObject(ParticlesStage.prototype, {
+
+ imageSrcs: [
+ "compass",
+ "console",
+ "contribute",
+ "debugger",
+ "inspector",
+ "layout",
+ "performance",
+ "script",
+ "shortcuts",
+ "standards",
+ "storage",
+ "styles",
+ "timeline"
+ ],
+ images: [],
+
+ initialize: function(benchmark)
+ {
+ Stage.prototype.initialize.call(this, benchmark);
+
+ var lastPromise;
+ var images = this.images;
+ this.imageSrcs.forEach(function(imageSrc) {
+ var promise = this._loadImage("../master/resources/" + imageSrc + "100.png");
+ if (!lastPromise)
+ lastPromise = promise;
+ else {
+ lastPromise = lastPromise.then(function(img) {
+ images.push(img);
+ return promise;
+ });
+ }
+ }, this);
+
+ lastPromise.then(function(img) {
+ images.push(img);
+ benchmark.readyPromise.resolve();
+ });
+ },
+
+ _loadImage: function(src) {
+ var img = new Image;
+ var promise = new SimplePromise;
+
+ img.onload = function(e) {
+ promise.resolve(e.target);
+ };
+
+ img.src = src;
+ return promise;
+ },
+
+ animate: function(timeDelta)
+ {
+ this.focusX = 0.5 + 0.5 * Math.sin(Stage.dateFractionalValue(10000) * Math.PI * 2);
+ timeDelta /= 4;
+ this.particles.forEach(function(particle) {
+ particle.animate(timeDelta);
+ });
+ },
+
+ createParticle: function()
+ {
+ return new Leaf(this);
+ },
+
+ willRemoveParticle: function(particle)
+ {
+ particle.element.remove();
+ }
+});
+
+LeavesBenchmark = Utilities.createSubclass(Benchmark,
+ function(options)
+ {
+ Benchmark.call(this, new ParticlesStage(), options);
+ }, {
+
+ waitUntilReady: function() {
+ this.readyPromise = new SimplePromise;
+ return this.readyPromise;
+ }
+
+});
+
+window.benchmarkClass = LeavesBenchmark;
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/multiply.js b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/multiply.js
new file mode 100644
index 0000000000..e93cfbb5b9
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/multiply.js
@@ -0,0 +1,119 @@
+(function() {
+
+var MultiplyStage = Utilities.createSubclass(Stage,
+ function()
+ {
+ Stage.call(this);
+ this.tiles = [];
+ this._offsetIndex = 0;
+ }, {
+
+ initialize: function(benchmark, options)
+ {
+ Stage.prototype.initialize.call(this, benchmark, options);
+ var tileSize = Math.round(this.size.height / 25);
+
+ // Fill the scene with elements
+ var x = Math.round((this.size.width - tileSize) / 2);
+ var y = Math.round((this.size.height - tileSize) / 2);
+ var tileStride = tileSize;
+ var direction = 0;
+ var spiralCounter = 2;
+ var nextIndex = 1;
+ var maxSide = Math.floor(y / tileStride) * 2 + 1;
+ this._centerSpiralCount = maxSide * maxSide;
+ for (var i = 0; i < this._centerSpiralCount; ++i) {
+ this._addTile(x, y, tileSize, Stage.randomInt(0, 359));
+
+ if (i == nextIndex) {
+ direction = (direction + 1) % 4;
+ spiralCounter++;
+ nextIndex += spiralCounter >> 1;
+ }
+ if (direction == 0)
+ x += tileStride;
+ else if (direction == 1)
+ y -= tileStride;
+ else if (direction == 2)
+ x -= tileStride;
+ else
+ y += tileStride;
+ }
+
+ this._sidePanelCount = maxSide * Math.floor((this.size.width - x) / tileStride) * 2;
+ for (var i = 0; i < this._sidePanelCount; ++i) {
+ var sideX = x + Math.floor(Math.floor(i / maxSide) / 2) * tileStride;
+ var sideY = y - tileStride * (i % maxSide);
+
+ if (Math.floor(i / maxSide) % 2 == 1)
+ sideX = this.size.width - sideX - tileSize + 1;
+ this._addTile(sideX, sideY, tileSize, Stage.randomInt(0, 359));
+ }
+ },
+
+ _addTile: function(x, y, tileSize, rotateDeg)
+ {
+ var tile = Utilities.createElement("div", { class: "div-" + Stage.randomInt(0,6) }, this.element);
+ var halfTileSize = tileSize / 2;
+ tile.style.left = x + 'px';
+ tile.style.top = y + 'px';
+ tile.style.width = tileSize + 'px';
+ tile.style.height = tileSize + 'px';
+ tile.style.visibility = "hidden";
+
+ var distance = 1 / tileSize * this.size.multiply(0.5).subtract(new Point(x + halfTileSize, y + halfTileSize)).length();
+ this.tiles.push({
+ element: tile,
+ rotate: rotateDeg,
+ step: Math.max(3, distance / 1.5),
+ distance: distance,
+ active: false
+ });
+ },
+
+ complexity: function()
+ {
+ return this._offsetIndex;
+ },
+
+ tune: function(count)
+ {
+ this._offsetIndex = Math.max(0, Math.min(this._offsetIndex + count, this.tiles.length));
+ this._distanceFactor = 1.5 * (1 - 0.5 * Math.max(this._offsetIndex - this._centerSpiralCount, 0) / this._sidePanelCount) / Math.sqrt(this._offsetIndex);
+ },
+
+ animate: function()
+ {
+ var progress = this._benchmark.timestamp % 10000 / 10000;
+ var bounceProgress = Math.sin(2 * Math.abs( 0.5 - progress));
+ var l = Utilities.lerp(bounceProgress, 20, 50);
+ var hslPrefix = "hsla(" + Utilities.lerp(progress, 0, 360) + ",100%,";
+
+ for (var i = 0; i < this._offsetIndex; ++i) {
+ var tile = this.tiles[i];
+ tile.active = true;
+ tile.element.style.visibility = "";
+ tile.rotate += tile.step;
+ tile.element.style.transform = "rotate(" + tile.rotate + "deg)";
+
+ var influence = Math.max(.01, 1 - (tile.distance * this._distanceFactor));
+ tile.element.style.backgroundColor = hslPrefix + l * Math.tan(influence / 1.25) + "%," + influence + ")";
+ }
+
+ for (var i = this._offsetIndex; i < this.tiles.length && this.tiles[i].active; ++i) {
+ this.tiles[i].active = false;
+ this.tiles[i].element.style.visibility = "hidden";
+ }
+ }
+});
+
+var MultiplyBenchmark = Utilities.createSubclass(Benchmark,
+ function(options)
+ {
+ Benchmark.call(this, new MultiplyStage(), options);
+ }
+);
+
+window.benchmarkClass = MultiplyBenchmark;
+
+}());
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/particles.js b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/particles.js
new file mode 100644
index 0000000000..cf474e4142
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/particles.js
@@ -0,0 +1,112 @@
+function Particle(stage)
+{
+ this.stage = stage;
+ this.rotater = Stage.randomRotater();
+ this.reset();
+ this.move();
+}
+
+Particle.prototype =
+{
+ sizeMinimum: 40,
+ sizeRange: 10,
+
+ reset: function()
+ {
+ var randSize = Math.round(Math.pow(Pseudo.random(), 4) * this.sizeRange + this.sizeMinimum);
+ this.size = new Point(randSize, randSize);
+ this.minPosition = this.size.center;
+ this.maxPosition = this.stage.size.subtract(this.minPosition);
+ },
+
+ animate: function(timeDelta)
+ {
+ this.rotater.next(timeDelta);
+
+ this.position = this.position.add(this.velocity.multiply(timeDelta));
+ this.velocity.y += 0.03;
+
+ // If particle is going to move off right side
+ if (this.position.x > this.maxPosition.x) {
+ if (this.velocity.x > 0)
+ this.velocity.x *= -1;
+ this.position.x = this.maxPosition.x;
+ } else if (this.position.x < this.minPosition.x) {
+ // If particle is going to move off left side
+ if (this.velocity.x < 0)
+ this.velocity.x *= -1;
+ this.position.x = this.minPosition.x;
+ }
+
+ // If particle is going to move off bottom side
+ if (this.position.y > this.maxPosition.y) {
+ // Adjust direction but maintain magnitude
+ var magnitude = this.velocity.length();
+ this.velocity.x *= 1.5 + .005 * this.size.x;
+ this.velocity = this.velocity.normalize().multiply(magnitude);
+ if (Math.abs(this.velocity.y) < 0.7)
+ this.reset();
+ else {
+ if (this.velocity.y > 0)
+ this.velocity.y *= -0.999;
+ this.position.y = this.maxPosition.y;
+ }
+ } else if (this.position.y < this.minPosition.y) {
+ // If particle is going to move off top side
+ var magnitude = this.velocity.length();
+ this.velocity.x *= 1.5 + .005 * this.size.x;
+ this.velocity = this.velocity.normalize().multiply(magnitude);
+ if (this.velocity.y < 0)
+ this.velocity.y *= -0.998;
+ this.position.y = this.minPosition.y;
+ }
+
+ this.move();
+ },
+
+ move: function()
+ {
+ }
+}
+
+ParticlesStage = Utilities.createSubclass(Stage,
+ function()
+ {
+ Stage.call(this);
+ this.particles = [];
+ }, {
+
+ animate: function(timeDelta)
+ {
+ timeDelta /= 4;
+ this.particles.forEach(function(particle) {
+ particle.animate(timeDelta);
+ });
+ },
+
+ tune: function(count)
+ {
+ if (count == 0)
+ return;
+
+ if (count > 0) {
+ for (var i = 0; i < count; ++i)
+ this.particles.push(this.createParticle());
+ return;
+ }
+
+ count = Math.min(-count, this.particles.length);
+
+ if (typeof(this.willRemoveParticle) == "function") {
+ for (var i = 0; i < count; ++i)
+ this.willRemoveParticle(this.particles[i]);
+ }
+
+ this.particles.splice(0, count);
+ },
+
+ complexity: function()
+ {
+ return this.particles.length;
+ }
+});
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/performance.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/performance.svg
new file mode 100644
index 0000000000..37c4e952c1
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/performance.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright © 2016 Apple Inc. All rights reserved. -->
+<svg width="48px" height="48px" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <path d="M 24 45.76 L 24 45.76 C 36.0177161 45.76 45.76 36.0177162 45.76 24 C 45.76 11.9822838 36.0177161 2.24 24 2.24 C 11.9822838 2.24 2.24 11.9822838 2.24 24 C 2.24 36.0177162 11.9822838 45.76 24 45.76 L 24 45.76 L 24 45.76 L 24 45.76 Z M 24 48 L 24 48 C 10.745166 48 -1.77635684e-14 37.254834 -1.77635684e-14 24 C -1.77635684e-14 10.745166 10.745166 2.84217094e-14 24 2.84217094e-14 C 37.254834 2.84217094e-14 48 10.745166 48 24 C 48 37.254834 37.254834 48 24 48 L 24 48 L 24 48 L 24 48 Z" fill="rgb(152, 188, 77)"/>
+ <path d="M 25.4586474 22.9633529 L 36.6273818 12.9367924 L 19.3784717 20.0882179 L 22.54035 25.0378408 L 11.3720064 35.0646845 L 28.6179627 27.9103051 L 25.4586474 22.9633529 L 25.4586474 22.9633529 Z" fill="white"/>
+</svg>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/performance100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/performance100.png
new file mode 100644
index 0000000000..3f8a187596
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/performance100.png
Binary files differ
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/script.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/script.svg
new file mode 100644
index 0000000000..5e3f9c1b03
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/script.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright © 2016 Apple Inc. All rights reserved. -->
+<svg width="48px" height="48px" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <path d="M 9.4057939 17.7395629 C 10.1528885 17.0482595 11.14598 16.6062505 12.2562501 16.6062505 C 14.6587038 16.6062505 16.5125003 18.7103026 16.5125003 20.8625007 C 16.5125003 20.8625007 18.178953 19.2008056 19.0121793 18.369958 C 21.6138782 15.7756868 26.817276 10.5871443 26.817276 10.5871443 C 26.817276 10.5871443 37.1931445 21.9632427 37.5748423 22.4630973 C 38.0895548 23.1371422 39.2154452 24.3686768 39.2154452 26.5456407 C 39.2154452 27.6292862 38.7691081 28.6850409 38.0240604 29.4729943 C 37.2725506 30.267782 21.5041804 45.9478026 22.256517 45.2395774 C 23.0871144 44.4575043 23.6062505 43.3509701 23.6062505 42.1437514 C 23.6062505 39.8308355 22.4995839 38.7247751 21.9516194 38.0693479 C 21.9377433 38.0527505 21.4369464 37.5002693 20.6469581 36.6292772 L 15.0937502 42.1437514 C 15.0937502 44.4944134 16.9993383 46.4000015 19.3500004 46.4000015 C 20.4737422 46.4000015 21.4957691 45.9558816 22.256517 45.2395774 L 22.256517 45.2395773 C 22.2567055 45.2393999 22.256895 45.2392214 22.2570855 45.2390419 C 23.0873513 44.4569993 23.6062505 43.3506946 23.6062505 42.1437514 C 23.6062505 39.8308355 22.4995839 38.7247751 21.9516194 38.0693479 C 21.4036549 37.4139207 10.6902909 25.670612 9.9591809 24.8251984 C 9.2280709 23.9797848 8 23.049163 8 20.8625007 C 8 19.6863826 8.5362909 18.5441335 9.4057939 17.7395629 C 8.5362926 18.5441317 24.254167 2.7911567 25.2247918 1.98986582 C 25.9645636 1.37915353 26.8917931 1 27.8625007 1 C 30.1068344 1 32.1634331 3.09747093 32.1634331 5.25625015 L 16.5125003 20.8625007 C 16.5125003 18.7103026 14.6587038 16.6062505 12.2562501 16.6062505 C 11.1459801 16.6062505 10.1528886 17.0482595 9.405794 17.7395627 L 9.4057939 17.7395629 Z" fill="none" stroke="rgb(153, 127, 166)" stroke-width="2.5"/>
+</svg>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/script100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/script100.png
new file mode 100644
index 0000000000..c2ea55ead7
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/script100.png
Binary files differ
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/shortcuts.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/shortcuts.svg
new file mode 100644
index 0000000000..edaa84963b
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/shortcuts.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright © 2016 Apple Inc. All rights reserved. -->
+<svg width="48px" height="48px" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <path d="M 5 35.8242187 C 5 39.7527757 8.1847243 42.9375 12.1132812 42.9375 C 16.0418382 42.9375 19.2265625 39.7527757 19.2265625 35.8242187 L 19.2265625 11.9442883 C 19.2265625 8.1847243 16.0418382 5 12.1132812 5 C 8.1847243 5 5 8.1847243 5 12.1132812 C 5 16.0418382 8.1847243 19.2265625 12.1132812 19.2265625 L 35.8928161 19.2265625 C 39.7527757 19.2265625 42.9375 16.0418382 42.9375 12.1132812 C 42.9375 8.1847243 39.7527757 5 35.8242188 5 C 31.8956618 5 28.7109375 8.1847243 28.7109375 12.1132812 L 28.7109375 35.8190088 C 28.7109375 39.7527757 31.8956618 42.9375 35.8242187 42.9375 C 39.7527757 42.9375 42.9375 39.7527757 42.9375 35.8242188 C 42.9375 31.8956618 39.7527757 28.7109375 35.8242187 28.7109375 L 12.1184912 28.7109375 C 8.1847243 28.7109375 5 31.8956618 5 35.8242187 Z" fill="none" stroke="rgb(0, 136, 204)" stroke-width="2.5"/>
+</svg>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/shortcuts100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/shortcuts100.png
new file mode 100644
index 0000000000..aeb23e0a40
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/shortcuts100.png
Binary files differ
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/standards.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/standards.svg
new file mode 100644
index 0000000000..ac1e6934d8
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/standards.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright © 2016 Apple Inc. All rights reserved. -->
+<svg width="48px" height="48px" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <path d="M 42.0710239 24.0177617 C 39.1538386 16.9070258 32.1617573 11.8990479 24 11.8990479 C 16.3635634 11.8990479 9.75107907 16.2831086 6.54212676 22.6716502 M 30.9761247 44.4830419 C 32.2260967 41.0462637 32.9749756 36.6675422 32.9749756 31.8990479 C 32.9749756 20.8533529 28.9567421 11.8990479 24 11.8990479 C 19.0432579 11.8990479 15.0250244 20.8533529 15.0250244 31.8990479 C 15.0250244 36.5317055 15.7318455 40.7964804 16.9182797 44.1870585 L 16.9182797 44.1870585 M 6.58618164 23.392334 C 6.58618164 25.4881886 14.5338788 27.1872144 24.3378601 27.1872144 C 34.1418414 27.1872144 42.0895386 25.4881886 42.0895386 23.392334 M 7.57792629 35.5492537 C 10.9596878 37.443268 17.049483 38.7070228 24 38.7070228 C 31.5250917 38.7070228 38.041274 37.2256916 41.204187 35.0669761 M 24.25 12.9990234 L 24.25 45" fill="none" stroke="white" stroke-width="2.5"/>
+ <path d="M 8.20156221 41.7446204 L 4.60455725 1.39999998 L 44.1294427 1.39999998 L 40.5286241 41.7383005 L 24.34281 46.2255399 L 8.20156221 41.7446204 Z" fill="none" stroke="#BF7600" stroke-width="2.5"/>
+</svg>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/standards100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/standards100.png
new file mode 100644
index 0000000000..ff386ff163
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/standards100.png
Binary files differ
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/storage.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/storage.svg
new file mode 100644
index 0000000000..c34a9ed255
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/storage.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright © 2016 Apple Inc. All rights reserved. -->
+<svg width="48px" height="48px" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <path d="M 39.9236499 31.5126111 C 41.869091 32.6498521 43 34.0625041 43 35.6923077 C 43 40.1632127 34.4896382 43 24 43 C 13.5103618 43 5 40.1632127 5 35.6923077 C 5 34.0625041 6.130909 32.6498521 8.07635005 31.5126111 C 9.14708175 31.9858647 10.3798534 32.4104194 11.7445378 32.7755154 C 9.22593316 33.7562269 7.92307692 34.9214488 7.92307692 35.6923077 C 7.92307692 36.4947878 9.3350136 37.7246485 12.0606138 38.728817 C 15.168606 39.8738668 19.433505 40.5384615 24 40.5384615 C 28.566495 40.5384615 32.831394 39.8738668 35.9393862 38.728817 C 38.6649864 37.7246485 40.0769231 36.4947878 40.0769231 35.6923077 C 40.0769231 34.9214488 38.7740668 33.7562269 36.2554622 32.7755154 C 37.6201466 32.4104194 38.8529182 31.9858647 39.9236499 31.5126111 Z M 39.9236499 19.8203034 C 41.869091 20.9575444 43 22.3701964 43 24 C 43 28.470905 34.4896382 31.3076923 24 31.3076923 C 13.5103618 31.3076923 5 28.470905 5 24 C 5 22.3701964 6.130909 20.9575444 8.07635005 19.8203034 C 9.06881359 20.2589632 10.2004933 20.6557834 11.4473978 21.0021956 C 9.12353139 22.0250817 7.92307692 23.2072017 7.92307692 24 C 7.92307692 24.8598001 9.3350136 26.177508 12.0606138 27.2534028 C 15.168606 28.4802419 19.433505 29.1923077 24 29.1923077 C 28.566495 29.1923077 32.831394 28.4802419 35.9393862 27.2534028 C 38.6649864 26.177508 40.0769231 24.8598001 40.0769231 24 C 40.0769231 23.2072017 38.8764686 22.0250817 36.5526022 21.0021956 C 37.7995067 20.6557834 38.9311864 20.2589632 39.9236499 19.8203034 Z M 43 12.3076923 C 43 7.83678727 34.4896382 5 24 5 C 13.5103618 5 5 7.83678727 5 12.3076923 C 5 16.7785973 13.5103618 19.6153846 24 19.6153846 C 34.4896382 19.6153846 43 16.7785973 43 12.3076923 Z M 12.0606138 15.3442016 C 9.3350136 14.3400331 7.92307692 13.1101724 7.92307692 12.3076923 C 7.92307692 11.5052122 9.3350136 10.2753515 12.0606138 9.27118298 C 15.168606 8.12613322 19.433505 7.46153846 24 7.46153846 C 28.566495 7.46153846 32.831394 8.12613322 35.9393862 9.27118298 C 38.6649864 10.2753515 40.0769231 11.5052122 40.0769231 12.3076923 C 40.0769231 13.1101724 38.6649864 14.3400331 35.9393862 15.3442016 C 32.831394 16.4892514 28.566495 17.1538462 24 17.1538462 C 19.433505 17.1538462 15.168606 16.4892514 12.0606138 15.3442016 Z" fill="rgb(153, 127, 166)"/>
+</svg>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/storage100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/storage100.png
new file mode 100644
index 0000000000..bc59d92fcf
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/storage100.png
Binary files differ
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/styles.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/styles.svg
new file mode 100644
index 0000000000..f50cff7d6d
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/styles.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright © 2016 Apple Inc. All rights reserved. -->
+<svg width="48px" height="48px" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <path d="M 32.2807541 19.800573 C 30.8515632 18.9532817 29.6775632 16.9314716 29.6582461 15.2582558 L 29.5886562 9.2305008 C 29.5694759 7.56913954 30.7023175 6.90315961 32.1417063 7.75649663 L 37.3271003 10.8306408 C 38.7562912 11.677932 39.9302912 13.6997422 39.9496083 15.3729579 L 40.0191983 21.400713 C 40.0383785 23.0620742 38.905537 23.7280542 37.4661481 22.8747171 L 32.2807541 19.800573 L 32.2807541 19.800573 L 32.2807541 19.800573 Z M 22.7106927 25.0325153 C 21.2837011 24.186528 20.1113895 22.1575845 20.0922204 20.4971883 L 19.9529996 8.43813667 C 19.9338489 6.77933205 21.0737602 6.11960178 22.5021209 6.96640082 L 32.8759556 13.1164953 C 34.3029471 13.9624827 35.4752587 15.9914262 35.4944279 17.6518224 L 35.6336486 29.710874 C 35.6527994 31.3696786 34.512888 32.0294089 33.0845273 31.1826098 L 22.7106927 25.0325153 L 22.7106927 25.0325153 L 22.7106927 25.0325153 Z M 11.6578029 32.7104298 C 9.75514746 31.5824467 8.19206532 28.8771886 8.16650648 26.6633271 L 7.98087883 10.5845916 C 7.95534449 8.37285211 9.47522625 7.49321175 11.3797072 8.62227714 L 25.2114868 16.8224031 C 27.1141422 17.9503863 28.6772243 20.6556443 28.7027831 22.8695059 L 28.8884108 38.9482414 C 28.9139451 41.1599809 27.3940634 42.0396212 25.4895824 40.9105558 L 11.6578029 32.7104298 L 11.6578029 32.7104298 L 11.6578029 32.7104298 Z" fill="none" stroke="rgb(191, 109, 113)" stroke-width="2.5"/>
+</svg>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/styles100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/styles100.png
new file mode 100644
index 0000000000..7bc9fffe9c
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/styles100.png
Binary files differ
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/svg-particles.js b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/svg-particles.js
new file mode 100644
index 0000000000..2ce24b56f1
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/svg-particles.js
@@ -0,0 +1,111 @@
+(function() {
+
+SVGParticle = Utilities.createSubclass(Particle,
+ function(stage)
+ {
+ var shapeId = "#shape-" + Stage.randomInt(1, stage.particleTypeCount);
+ this.isClipPath = Stage.randomBool();
+ if (this.isClipPath) {
+ this.element = Utilities.createSVGElement("rect", {
+ x: 0,
+ y: 0,
+ "clip-path": "url(" + shapeId + ")"
+ }, {}, stage.element);
+ } else {
+ var shapePath = document.querySelector(shapeId + " path");
+ this.element = shapePath.cloneNode();
+ stage.element.appendChild(this.element);
+ }
+
+ this.gradient = document.getElementById("default-gradient").cloneNode(true);
+ this.gradient.id = "gradient-" + stage.gradientsCounter++;
+ stage.gradientsDefs.appendChild(this.gradient);
+ this.element.setAttribute("fill", "url(#" + this.gradient.id + ")");
+
+ Particle.call(this, stage);
+ }, {
+
+ sizeMinimum: 30,
+ sizeRange: 40,
+
+ reset: function()
+ {
+ Particle.prototype.reset.call(this);
+
+ this.position = Stage.randomElementInArray(this.stage.emitLocation);
+
+ var velocityMagnitude = Stage.random(.5, 2.5);
+ var angle = Stage.randomInt(0, this.stage.emitSteps) / this.stage.emitSteps * Math.PI * 2 + Stage.dateCounterValue(1000) * this.stage.emissionSpin + velocityMagnitude;
+ this.velocity = new Point(Math.sin(angle), Math.cos(angle))
+ .multiply(velocityMagnitude);
+
+ if (this.isClipPath) {
+ this.element.setAttribute("width", this.size.x);
+ this.element.setAttribute("height", this.size.y);
+ this.transformSuffix = " translate(-" + this.size.center.x + ",-" + this.size.center.y + ")";
+ } else
+ this.transformSuffix = " scale(" + this.size.x + ") translate(-.5,-.5)";
+
+ this.stage.colorOffset = (this.stage.colorOffset + .5) % 360;
+
+ var transform = this.stage.element.createSVGTransform();
+ transform.setRotate(Stage.randomInt(0, 359), 0, 0);
+ this.gradient.gradientTransform.baseVal.initialize(transform);
+
+ var stops = this.gradient.querySelectorAll("stop");
+ stops[0].setAttribute("stop-color", "hsl(" + this.stage.colorOffset + ", 70%, 45%)");
+ stops[1].setAttribute("stop-color", "hsl(" + ((this.stage.colorOffset + Stage.randomInt(50,100)) % 360) + ", 70%, 65%)");
+ },
+
+ move: function()
+ {
+ this.element.setAttribute("transform", "translate(" + this.position.x + "," + this.position.y + ") " + this.rotater.rotate(Point.zero) + this.transformSuffix);
+ }
+});
+
+SVGParticleStage = Utilities.createSubclass(ParticlesStage,
+ function()
+ {
+ ParticlesStage.call(this);
+ }, {
+
+ initialize: function(benchmark)
+ {
+ ParticlesStage.prototype.initialize.call(this, benchmark);
+ this.emissionSpin = Stage.random(0, 3);
+ this.emitSteps = Stage.randomInt(4, 6);
+ this.emitLocation = [
+ new Point(this.size.x * .25, this.size.y * .333),
+ new Point(this.size.x * .5, this.size.y * .25),
+ new Point(this.size.x * .75, this.size.y * .333)
+ ];
+ this.colorOffset = Stage.randomInt(0, 359);
+
+ this.particleTypeCount = document.querySelectorAll(".shape").length;
+ this.gradientsDefs = document.getElementById("gradients");
+ this.gradientsCounter = 0;
+ },
+
+ createParticle: function()
+ {
+ return new SVGParticle(this);
+ },
+
+ willRemoveParticle: function(particle)
+ {
+ particle.element.remove();
+ if (particle.gradient)
+ particle.gradient.remove();
+ }
+});
+
+SVGParticleBenchmark = Utilities.createSubclass(Benchmark,
+ function(options)
+ {
+ Benchmark.call(this, new SVGParticleStage(), options);
+ }
+);
+
+window.benchmarkClass = SVGParticleBenchmark;
+
+})();
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/text.js b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/text.js
new file mode 100644
index 0000000000..c7ebe464b3
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/text.js
@@ -0,0 +1,116 @@
+(function() {
+
+var TextStage = Utilities.createSubclass(Stage,
+ function()
+ {
+ Stage.call(this);
+
+ this.testElements = [];
+ this._offsetIndex = 0;
+ }, {
+
+ shadowFalloff: new UnitBezier(new Point(0.015, 0.750), new Point(0.755, 0.235)),
+ shimmerAverage: 0,
+ shimmerMax: 0.5,
+ millisecondsPerRotation: 1000 / (.26 * Math.PI * 2),
+ particleDistanceX: 1.5,
+ particleDistanceY: .5,
+ lightnessMin: 13,
+ lightnessMax: 94,
+ gradients: [
+ [10, 176, 176, 209, 148, 140],
+ [171, 120, 154, 245, 196, 154],
+ [224, 99, 99, 71, 134, 148],
+ [101, 100, 117, 80, 230, 175],
+ [232, 165, 30, 69, 186, 172]
+ ],
+
+ initialize: function(benchmark)
+ {
+ Stage.prototype.initialize.call(this, benchmark);
+
+ this._template = document.getElementById("template");
+ this._offset = this.size.subtract(Point.elementClientSize(this._template)).multiply(.5);
+ this._template.style.left = this._offset.width + "px";
+ this._template.style.top = this._offset.height + "px";
+
+ this._stepProgress = 0;
+ },
+
+ tune: function(count)
+ {
+ if (count == 0)
+ return;
+
+ if (count < 0) {
+ this._offsetIndex = Math.max(this._offsetIndex + count, 0);
+ for (var i = this._offsetIndex; i < this.testElements.length; ++i)
+ this.testElements[i].style.visibility = "hidden";
+
+ this._stepProgress = 1 / this._offsetIndex;
+ return;
+ }
+
+ this._offsetIndex = this._offsetIndex + count;
+ this._stepProgress = 1 / this._offsetIndex;
+
+ var index = Math.min(this._offsetIndex, this.testElements.length);
+ for (var i = 0; i < index; ++i)
+ this.testElements[i].style.visibility = "visible";
+
+ if (this._offsetIndex <= this.testElements.length)
+ return;
+
+ for (var i = this.testElements.length; i < this._offsetIndex; ++i) {
+ var clone = this._template.cloneNode(true);
+ this.testElements.push(clone);
+ this.element.insertBefore(clone, this.element.firstChild);
+ }
+ },
+
+ animate: function(timeDelta) {
+ var angle = Stage.dateCounterValue(this.millisecondsPerRotation);
+
+ var progress = 0;
+ var stepX = Math.sin(angle) * this.particleDistanceX;
+ var stepY = Math.cos(angle) * this.particleDistanceY;
+ var x = -stepX * 3;
+ var y = -stepY * 3;
+ var gradient = this.gradients[Math.floor(angle/(Math.PI * 2)) % this.gradients.length];
+ var offset = Stage.dateCounterValue(200);
+ this._template.style.transform = "translate(" + Math.floor(x) + "px," + Math.floor(y) + "px)";
+ for (var i = 0; i < this._offsetIndex; ++i) {
+ var element = this.testElements[i];
+
+ var colorProgress = this.shadowFalloff.solve(progress);
+ var shimmer = Math.sin(offset - colorProgress);
+ colorProgress = Math.max(Math.min(colorProgress + Utilities.lerp(shimmer, this.shimmerAverage, this.shimmerMax), 1), 0);
+ var r = Math.round(Utilities.lerp(colorProgress, gradient[0], gradient[3]));
+ var g = Math.round(Utilities.lerp(colorProgress, gradient[1], gradient[4]));
+ var b = Math.round(Utilities.lerp(colorProgress, gradient[2], gradient[5]));
+ element.style.color = "rgb(" + r + "," + g + "," + b + ")";
+
+ x += stepX;
+ y += stepY;
+ element.style.transform = "translate(" + Math.floor(x) + "px," + Math.floor(y) + "px)";
+
+ progress += this._stepProgress;
+ }
+ },
+
+ complexity: function()
+ {
+ return 1 + this._offsetIndex;
+ }
+});
+
+var TextBenchmark = Utilities.createSubclass(Benchmark,
+ function(options)
+ {
+ Benchmark.call(this, new TextStage(), options);
+ }
+);
+
+window.benchmarkClass = TextBenchmark;
+
+}());
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/timeline.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/timeline.svg
new file mode 100644
index 0000000000..cd1e8a4e20
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/timeline.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright © 2016 Apple Inc. All rights reserved. -->
+<svg width="48px" height="48px" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <path d="M 24 45.76 L 24 45.76 C 36.0177161 45.76 45.76 36.0177162 45.76 24 C 45.76 11.9822838 36.0177161 2.24 24 2.24 C 11.9822838 2.24 2.24 11.9822838 2.24 24 C 2.24 36.0177162 11.9822838 45.76 24 45.76 L 24 45.76 L 24 45.76 L 24 45.76 Z M 24 48 L 24 48 C 10.745166 48 0 37.254834 0 24 C 0 10.745166 10.745166 0 24 0 C 37.254834 0 48 10.745166 48 24 C 48 37.254834 37.254834 48 24 48 L 24 48 L 24 48 L 24 48 Z" fill="rgb(0, 136, 204)"/>
+ <path d="M 24.625 7.57617187 L 24.625 24.5833333 L 15 24.5833333" fill="none" stroke="white" stroke-width="2.5"/>
+</svg>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/timeline100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/timeline100.png
new file mode 100644
index 0000000000..b9839f8447
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/timeline100.png
Binary files differ
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/svg-particles.html b/third_party/webkit/PerformanceTests/MotionMark/tests/master/svg-particles.html
new file mode 100644
index 0000000000..46a19369da
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/svg-particles.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="../resources/stage.css">
+</head>
+<body>
+ <svg id="stage">
+ <defs id="gradients">
+ <linearGradient id="default-gradient">
+ <stop offset="0%"/>
+ <stop offset="100%"/>
+ </linearGradient>
+ </defs>
+ <defs id="shapes">
+ <clipPath id="shape-1" class="shape heart" clipPathUnits="objectBoundingBox">
+ <path d="M0.5,0.214 C0.466,0.164 0.369,0.09 0.267,0.092 C0.137,0.093 -0,0.186 -0,0.345 C-0,0.659 0.395,0.655 0.5,0.938 C0.605,0.655 1,0.659 1,0.345 C1,0.186 0.863,0.093 0.733,0.092 C0.631,0.09 0.534,0.164 0.5,0.214 z"/>
+ </clipPath>
+ <clipPath id="shape-2" class="shape club" clipPathUnits="objectBoundingBox">
+ <path d="M0.5,0.018 C0.62,0.018 0.718,0.115 0.718,0.235 C0.718,0.31 0.679,0.377 0.618,0.418 C0.657,0.393 0.703,0.382 0.749,0.381 C0.869,0.381 0.967,0.468 0.967,0.588 C0.967,0.709 0.869,0.806 0.749,0.806 C0.664,0.805 0.578,0.756 0.542,0.677 C0.538,0.799 0.605,0.918 0.708,0.982 C0.593,0.941 0.407,0.941 0.292,0.982 C0.397,0.917 0.461,0.799 0.459,0.676 C0.422,0.756 0.337,0.804 0.251,0.806 C0.131,0.806 0.033,0.709 0.033,0.588 C0.033,0.468 0.131,0.381 0.251,0.381 C0.298,0.38 0.342,0.395 0.382,0.418 C0.319,0.378 0.284,0.309 0.282,0.235 C0.282,0.115 0.38,0.018 0.5,0.018 z"/>
+ </clipPath>
+ <clipPath id="shape-3" class="shape spade" clipPathUnits="objectBoundingBox">
+ <path d="M0.301,0.982 C0.374,0.941 0.469,0.804 0.469,0.72 C0.374,0.857 0.039,0.825 0.049,0.563 C0.059,0.28 0.406,0.269 0.5,0.018 C0.594,0.269 0.941,0.28 0.951,0.563 C0.961,0.825 0.626,0.857 0.531,0.72 C0.531,0.804 0.626,0.941 0.699,0.982 C0.584,0.941 0.416,0.941 0.301,0.982"/>
+ </clipPath>
+ <clipPath id="shape-4" class="shape diamond" clipPathUnits="objectBoundingBox">
+ <path d="M0.495,0 C0.424,0.153 0.199,0.439 0.128,0.5 C0.199,0.561 0.424,0.847 0.495,1 C0.566,0.847 0.791,0.561 0.862,0.5 C0.791,0.439 0.566,0.153 0.495,0 z"/>
+ </clipPath>
+ </defs>
+ </svg>
+ <script src="../../resources/strings.js"></script>
+ <script src="../../resources/extensions.js"></script>
+ <script src="../../resources/statistics.js"></script>
+ <script src="../resources/math.js"></script>
+ <script src="../resources/main.js"></script>
+ <script src="resources/particles.js"></script>
+ <script src="resources/svg-particles.js"></script>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/text.html b/third_party/webkit/PerformanceTests/MotionMark/tests/master/text.html
new file mode 100644
index 0000000000..5e94b8ce95
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/text.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="../resources/stage.css">
+ <style type="text/css">
+
+ #stage {
+ font-family: Helvetica;
+ font-size: 52px;
+ background-color: #313534;
+ }
+ @media (max-width: 900px) {
+ #stage {
+ font-size: 40px;
+ }
+ }
+ @media (max-width: 568px) {
+ #stage {
+ font-size: 28px;
+ }
+ }
+
+ #stage div {
+ width: 80%;
+ height: 90%;
+ position: absolute;
+ text-align: center;
+ }
+ #template {
+ color: #FCFCFC;
+ }
+ table {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ }
+ td {
+ width: 33%;
+ }
+ tr {
+ height: 20%;
+ }
+ </style>
+</head>
+<body>
+ <div id="stage">
+ <div id="template">
+ <table>
+ <tbody>
+ <tr>
+ <td>σχέδιο</td>
+ <td>设计</td>
+ <td>suunnittelu</td>
+ </tr>
+ <tr>
+ <td>design</td>
+ <td>дизайн</td>
+ <td class="rtl">تصميم</td>
+ </tr>
+ <tr>
+ <td>디자인</td>
+ <td>conception</td>
+ <td>デザイン</td>
+ </tr>
+ <tr>
+ <td>konstruktion</td>
+ <td class="rtl">עיצוב</td>
+ <td>diseño</td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ <script src="../../resources/strings.js"></script>
+ <script src="../../resources/extensions.js"></script>
+ <script src="../../resources/statistics.js"></script>
+ <script src="../resources/math.js"></script>
+ <script src="../resources/main.js"></script>
+ <script src="resources/text.js"></script>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/resources/main.js b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/main.js
new file mode 100644
index 0000000000..b9776d571e
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/main.js
@@ -0,0 +1,934 @@
+Sampler = Utilities.createClass(
+ function(seriesCount, expectedSampleCount, processor)
+ {
+ this._processor = processor;
+
+ this.samples = [];
+ for (var i = 0; i < seriesCount; ++i) {
+ var array = new Array(expectedSampleCount);
+ array.fill(0);
+ this.samples[i] = array;
+ }
+ this.sampleCount = 0;
+ }, {
+
+ record: function() {
+ // Assume that arguments.length == this.samples.length
+ for (var i = 0; i < arguments.length; i++) {
+ this.samples[i][this.sampleCount] = arguments[i];
+ }
+ ++this.sampleCount;
+ },
+
+ processSamples: function()
+ {
+ var results = {};
+
+ // Remove unused capacity
+ this.samples = this.samples.map(function(array) {
+ return array.slice(0, this.sampleCount);
+ }, this);
+
+ this._processor.processSamples(results);
+
+ return results;
+ }
+});
+
+Controller = Utilities.createClass(
+ function(benchmark, options)
+ {
+ // Initialize timestamps relative to the start of the benchmark
+ // In start() the timestamps are offset by the start timestamp
+ this._startTimestamp = 0;
+ this._endTimestamp = options["test-interval"];
+ // Default data series: timestamp, complexity, estimatedFrameLength
+ var sampleSize = options["sample-capacity"] || (60 * options["test-interval"] / 1000);
+ this._sampler = new Sampler(options["series-count"] || 3, sampleSize, this);
+ this._marks = {};
+
+ this._frameLengthEstimator = new SimpleKalmanEstimator(options["kalman-process-error"], options["kalman-measurement-error"]);
+ this._isFrameLengthEstimatorEnabled = true;
+
+ // Length of subsequent intervals; a value of 0 means use no intervals
+ this.intervalSamplingLength = 100;
+
+ this.initialComplexity = 1;
+ }, {
+
+ set isFrameLengthEstimatorEnabled(enabled) {
+ this._isFrameLengthEstimatorEnabled = enabled;
+ },
+
+ start: function(startTimestamp, stage)
+ {
+ this._startTimestamp = startTimestamp;
+ this._endTimestamp += startTimestamp;
+ this._previousTimestamp = startTimestamp;
+ this._measureAndResetInterval(startTimestamp);
+ this.recordFirstSample(startTimestamp, stage);
+ },
+
+ recordFirstSample: function(startTimestamp, stage)
+ {
+ this._sampler.record(startTimestamp, stage.complexity(), -1);
+ this.mark(Strings.json.samplingStartTimeOffset, startTimestamp);
+ },
+
+ mark: function(comment, timestamp, data) {
+ data = data || {};
+ data.time = timestamp;
+ data.index = this._sampler.sampleCount;
+ this._marks[comment] = data;
+ },
+
+ containsMark: function(comment) {
+ return comment in this._marks;
+ },
+
+ _measureAndResetInterval: function(currentTimestamp)
+ {
+ var sampleCount = this._sampler.sampleCount;
+ var averageFrameLength = 0;
+
+ if (this._intervalEndTimestamp) {
+ var intervalStartTimestamp = this._sampler.samples[0][this._intervalStartIndex];
+ averageFrameLength = (currentTimestamp - intervalStartTimestamp) / (sampleCount - this._intervalStartIndex);
+ }
+
+ this._intervalStartIndex = sampleCount;
+ this._intervalEndTimestamp = currentTimestamp + this.intervalSamplingLength;
+
+ return averageFrameLength;
+ },
+
+ update: function(timestamp, stage)
+ {
+ var lastFrameLength = timestamp - this._previousTimestamp;
+ this._previousTimestamp = timestamp;
+
+ var frameLengthEstimate = -1, intervalAverageFrameLength = -1;
+ var didFinishInterval = false;
+ if (!this.intervalSamplingLength) {
+ if (this._isFrameLengthEstimatorEnabled) {
+ this._frameLengthEstimator.sample(lastFrameLength);
+ frameLengthEstimate = this._frameLengthEstimator.estimate;
+ }
+ } else if (timestamp >= this._intervalEndTimestamp) {
+ var intervalStartTimestamp = this._sampler.samples[0][this._intervalStartIndex];
+ intervalAverageFrameLength = this._measureAndResetInterval(timestamp);
+ if (this._isFrameLengthEstimatorEnabled) {
+ this._frameLengthEstimator.sample(intervalAverageFrameLength);
+ frameLengthEstimate = this._frameLengthEstimator.estimate;
+ }
+ didFinishInterval = true;
+ this.didFinishInterval(timestamp, stage, intervalAverageFrameLength);
+ }
+
+ this._sampler.record(timestamp, stage.complexity(), frameLengthEstimate);
+ this.tune(timestamp, stage, lastFrameLength, didFinishInterval, intervalAverageFrameLength);
+ },
+
+ didFinishInterval: function(timestamp, stage, intervalAverageFrameLength)
+ {
+ },
+
+ tune: function(timestamp, stage, lastFrameLength, didFinishInterval, intervalAverageFrameLength)
+ {
+ },
+
+ shouldStop: function(timestamp)
+ {
+ return timestamp > this._endTimestamp;
+ },
+
+ results: function()
+ {
+ return this._sampler.processSamples();
+ },
+
+ _processComplexitySamples: function(complexitySamples, complexityAverageSamples)
+ {
+ complexityAverageSamples.addField(Strings.json.complexity, 0);
+ complexityAverageSamples.addField(Strings.json.frameLength, 1);
+ complexityAverageSamples.addField(Strings.json.measurements.stdev, 2);
+
+ complexitySamples.sort(function(a, b) {
+ return complexitySamples.getFieldInDatum(a, Strings.json.complexity) - complexitySamples.getFieldInDatum(b, Strings.json.complexity);
+ });
+
+ // Samples averaged based on complexity
+ var currentComplexity = -1;
+ var experimentAtComplexity;
+ function addSample() {
+ var mean = experimentAtComplexity.mean();
+ var stdev = experimentAtComplexity.standardDeviation();
+
+ var averageSample = complexityAverageSamples.createDatum();
+ complexityAverageSamples.push(averageSample);
+ complexityAverageSamples.setFieldInDatum(averageSample, Strings.json.complexity, currentComplexity);
+ complexityAverageSamples.setFieldInDatum(averageSample, Strings.json.frameLength, mean);
+ complexityAverageSamples.setFieldInDatum(averageSample, Strings.json.measurements.stdev, stdev);
+ }
+ complexitySamples.forEach(function(sample) {
+ var sampleComplexity = complexitySamples.getFieldInDatum(sample, Strings.json.complexity);
+ if (sampleComplexity != currentComplexity) {
+ if (currentComplexity > -1)
+ addSample();
+
+ currentComplexity = sampleComplexity;
+ experimentAtComplexity = new Experiment;
+ }
+ experimentAtComplexity.sample(complexitySamples.getFieldInDatum(sample, Strings.json.frameLength));
+ });
+ // Finish off the last one
+ addSample();
+ },
+
+ processSamples: function(results)
+ {
+ var complexityExperiment = new Experiment;
+ var smoothedFrameLengthExperiment = new Experiment;
+
+ var samples = this._sampler.samples;
+
+ for (var markName in this._marks)
+ this._marks[markName].time -= this._startTimestamp;
+ results[Strings.json.marks] = this._marks;
+
+ results[Strings.json.samples] = {};
+
+ var controllerSamples = new SampleData;
+ results[Strings.json.samples][Strings.json.controller] = controllerSamples;
+
+ controllerSamples.addField(Strings.json.time, 0);
+ controllerSamples.addField(Strings.json.complexity, 1);
+ controllerSamples.addField(Strings.json.frameLength, 2);
+ controllerSamples.addField(Strings.json.smoothedFrameLength, 3);
+
+ var complexitySamples = new SampleData(controllerSamples.fieldMap);
+ results[Strings.json.samples][Strings.json.complexity] = complexitySamples;
+
+ samples[0].forEach(function(timestamp, i) {
+ var sample = controllerSamples.createDatum();
+ controllerSamples.push(sample);
+ complexitySamples.push(sample);
+
+ // Represent time in milliseconds
+ controllerSamples.setFieldInDatum(sample, Strings.json.time, timestamp - this._startTimestamp);
+ controllerSamples.setFieldInDatum(sample, Strings.json.complexity, samples[1][i]);
+
+ if (i == 0)
+ controllerSamples.setFieldInDatum(sample, Strings.json.frameLength, 1000/60);
+ else
+ controllerSamples.setFieldInDatum(sample, Strings.json.frameLength, timestamp - samples[0][i - 1]);
+
+ if (samples[2][i] != -1)
+ controllerSamples.setFieldInDatum(sample, Strings.json.smoothedFrameLength, samples[2][i]);
+ }, this);
+
+ var complexityAverageSamples = new SampleData;
+ results[Strings.json.samples][Strings.json.complexityAverage] = complexityAverageSamples;
+ this._processComplexitySamples(complexitySamples, complexityAverageSamples);
+ }
+});
+
+FixedController = Utilities.createSubclass(Controller,
+ function(benchmark, options)
+ {
+ Controller.call(this, benchmark, options);
+ this.initialComplexity = options["complexity"];
+ this.intervalSamplingLength = 0;
+ }
+);
+
+StepController = Utilities.createSubclass(Controller,
+ function(benchmark, options)
+ {
+ Controller.call(this, benchmark, options);
+ this.initialComplexity = options["complexity"];
+ this.intervalSamplingLength = 0;
+ this._stepped = false;
+ this._stepTime = options["test-interval"] / 2;
+ }, {
+
+ start: function(startTimestamp, stage)
+ {
+ Controller.prototype.start.call(this, startTimestamp, stage);
+ this._stepTime += startTimestamp;
+ },
+
+ tune: function(timestamp, stage)
+ {
+ if (this._stepped || timestamp < this._stepTime)
+ return;
+
+ this.mark(Strings.json.samplingEndTimeOffset, timestamp);
+ this._stepped = true;
+ stage.tune(stage.complexity() * 3);
+ }
+});
+
+AdaptiveController = Utilities.createSubclass(Controller,
+ function(benchmark, options)
+ {
+ // Data series: timestamp, complexity, estimatedIntervalFrameLength
+ Controller.call(this, benchmark, options);
+
+ // All tests start at 0, so we expect to see 60 fps quickly.
+ this._samplingTimestamp = options["test-interval"] / 2;
+ this._startedSampling = false;
+ this._targetFrameRate = options["frame-rate"];
+ this._pid = new PIDController(this._targetFrameRate);
+
+ this._intervalFrameCount = 0;
+ this._numberOfFramesToMeasurePerInterval = 4;
+ }, {
+
+ start: function(startTimestamp, stage)
+ {
+ Controller.prototype.start.call(this, startTimestamp, stage);
+
+ this._samplingTimestamp += startTimestamp;
+ this._intervalTimestamp = startTimestamp;
+ },
+
+ recordFirstSample: function(startTimestamp, stage)
+ {
+ this._sampler.record(startTimestamp, stage.complexity(), -1);
+ },
+
+ update: function(timestamp, stage)
+ {
+ if (!this._startedSampling && timestamp >= this._samplingTimestamp) {
+ this._startedSampling = true;
+ this.mark(Strings.json.samplingStartTimeOffset, this._samplingTimestamp);
+ }
+
+ // Start the work for the next frame.
+ ++this._intervalFrameCount;
+
+ if (this._intervalFrameCount < this._numberOfFramesToMeasurePerInterval) {
+ this._sampler.record(timestamp, stage.complexity(), -1);
+ return;
+ }
+
+ // Adjust the test to reach the desired FPS.
+ var intervalLength = timestamp - this._intervalTimestamp;
+ this._frameLengthEstimator.sample(intervalLength / this._numberOfFramesToMeasurePerInterval);
+ var intervalEstimatedFrameRate = 1000 / this._frameLengthEstimator.estimate;
+ var tuneValue = -this._pid.tune(timestamp - this._startTimestamp, intervalLength, intervalEstimatedFrameRate);
+ tuneValue = tuneValue > 0 ? Math.floor(tuneValue) : Math.ceil(tuneValue);
+ stage.tune(tuneValue);
+
+ this._sampler.record(timestamp, stage.complexity(), this._frameLengthEstimator.estimate);
+
+ // Start the next interval.
+ this._intervalFrameCount = 0;
+ this._intervalTimestamp = timestamp;
+ }
+});
+
+RampController = Utilities.createSubclass(Controller,
+ function(benchmark, options)
+ {
+ // The tier warmup takes at most 5 seconds
+ options["sample-capacity"] = (options["test-interval"] / 1000 + 5) * 60;
+ Controller.call(this, benchmark, options);
+
+ // Initially start with a tier test to find the bounds
+ // The number of objects in a tier test is 10^|_tier|
+ this._tier = -.5;
+ // The timestamp is first set after the first interval completes
+ this._tierStartTimestamp = 0;
+ this._minimumComplexity = 1;
+ this._maximumComplexity = 1;
+
+ // After the tier range is determined, figure out the number of ramp iterations
+ var minimumRampLength = 3000;
+ var totalRampIterations = Math.max(1, Math.floor(this._endTimestamp / minimumRampLength));
+ // Give a little extra room to run since the ramps won't be exactly this length
+ this._rampLength = Math.floor((this._endTimestamp - totalRampIterations * this.intervalSamplingLength) / totalRampIterations);
+ this._rampDidWarmup = false;
+ this._rampRegressions = [];
+
+ this._finishedTierSampling = false;
+ this._changePointEstimator = new Experiment;
+ this._minimumComplexityEstimator = new Experiment;
+ // Estimates all frames within an interval
+ this._intervalFrameLengthEstimator = new Experiment;
+ }, {
+
+ // If the engine can handle the tier's complexity at the desired frame rate, test for a short
+ // period, then move on to the next tier
+ tierFastTestLength: 250,
+ // If the engine is under stress, let the test run a little longer to let the measurement settle
+ tierSlowTestLength: 750,
+
+ rampWarmupLength: 200,
+
+ // Used for regression calculations in the ramps
+ frameLengthDesired: 1000/60,
+ // Add some tolerance; frame lengths shorter than this are considered to be @ the desired frame length
+ frameLengthDesiredThreshold: 1000/58,
+ // During tier sampling get at least this slow to find the right complexity range
+ frameLengthTierThreshold: 1000/30,
+ // Try to make each ramp get this slow so that we can cross the break point
+ frameLengthRampLowerThreshold: 1000/45,
+ // Do not let the regression calculation at the maximum complexity of a ramp get slower than this threshold
+ frameLengthRampUpperThreshold: 1000/20,
+
+ start: function(startTimestamp, stage)
+ {
+ Controller.prototype.start.call(this, startTimestamp, stage);
+ this._rampStartTimestamp = 0;
+ this.intervalSamplingLength = 100;
+ },
+
+ didFinishInterval: function(timestamp, stage, intervalAverageFrameLength)
+ {
+ if (!this._finishedTierSampling) {
+ if (this._tierStartTimestamp > 0 && timestamp < this._tierStartTimestamp + this.tierFastTestLength)
+ return;
+
+ var currentComplexity = stage.complexity();
+ var currentFrameLength = this._frameLengthEstimator.estimate;
+ if (currentFrameLength < this.frameLengthTierThreshold) {
+ var isAnimatingAt60FPS = currentFrameLength < this.frameLengthDesiredThreshold;
+ var hasFinishedSlowTierTest = timestamp > this._tierStartTimestamp + this.tierSlowTestLength;
+
+ if (!isAnimatingAt60FPS && !hasFinishedSlowTierTest)
+ return;
+
+ // We're measuring at 60 fps, so quickly move on to the next tier, or
+ // we've slower than 60 fps, but we've let this tier run long enough to
+ // get an estimate
+ this._lastTierComplexity = currentComplexity;
+ this._lastTierFrameLength = currentFrameLength;
+
+ this._tier += .5;
+ var nextTierComplexity = Math.round(Math.pow(10, this._tier));
+ stage.tune(nextTierComplexity - currentComplexity);
+
+ // Some tests may be unable to go beyond a certain capacity. If so, don't keep moving up tiers
+ if (stage.complexity() - currentComplexity > 0 || nextTierComplexity == 1) {
+ this._tierStartTimestamp = timestamp;
+ this.mark("Complexity: " + nextTierComplexity, timestamp);
+ return;
+ }
+ } else if (timestamp < this._tierStartTimestamp + this.tierSlowTestLength)
+ return;
+
+ this._finishedTierSampling = true;
+ this.isFrameLengthEstimatorEnabled = false;
+ this.intervalSamplingLength = 120;
+
+ // Extend the test length so that the full test length is made of the ramps
+ this._endTimestamp += timestamp;
+ this.mark(Strings.json.samplingStartTimeOffset, timestamp);
+
+ this._minimumComplexity = 1;
+ this._possibleMinimumComplexity = this._minimumComplexity;
+ this._minimumComplexityEstimator.sample(this._minimumComplexity);
+
+ // Sometimes this last tier will drop the frame length well below the threshold.
+ // Avoid going down that far since it means fewer measurements are taken in the 60 fps area.
+ // Interpolate a maximum complexity that gets us around the lowest threshold.
+ // Avoid doing this calculation if we never get out of the first tier (where this._lastTierComplexity is undefined).
+ if (this._lastTierComplexity && this._lastTierComplexity != currentComplexity)
+ this._maximumComplexity = Math.floor(Utilities.lerp(Utilities.progressValue(this.frameLengthTierThreshold, this._lastTierFrameLength, currentFrameLength), this._lastTierComplexity, currentComplexity));
+ else {
+ // If the browser is capable of handling the most complex version of the test, use that
+ this._maximumComplexity = currentComplexity;
+ }
+ this._possibleMaximumComplexity = this._maximumComplexity;
+
+ // If we get ourselves onto a ramp where the maximum complexity does not yield slow enough FPS,
+ // We'll use this as a boundary to find a higher maximum complexity for the next ramp
+ this._lastTierComplexity = currentComplexity;
+ this._lastTierFrameLength = currentFrameLength;
+
+ // First ramp
+ stage.tune(this._maximumComplexity - currentComplexity);
+ this._rampDidWarmup = false;
+ // Start timestamp represents start of ramp iteration and warm up
+ this._rampStartTimestamp = timestamp;
+ return;
+ }
+
+ if ((timestamp - this._rampStartTimestamp) < this.rampWarmupLength)
+ return;
+
+ if (this._rampDidWarmup)
+ return;
+
+ this._rampDidWarmup = true;
+ this._currentRampLength = this._rampStartTimestamp + this._rampLength - timestamp;
+ // Start timestamp represents start of ramp down, after warm up
+ this._rampStartTimestamp = timestamp;
+ this._rampStartIndex = this._sampler.sampleCount;
+ },
+
+ tune: function(timestamp, stage, lastFrameLength, didFinishInterval, intervalAverageFrameLength)
+ {
+ if (!this._rampDidWarmup)
+ return;
+
+ this._intervalFrameLengthEstimator.sample(lastFrameLength);
+ if (!didFinishInterval)
+ return;
+
+ var currentComplexity = stage.complexity();
+ var intervalFrameLengthMean = this._intervalFrameLengthEstimator.mean();
+ var intervalFrameLengthStandardDeviation = this._intervalFrameLengthEstimator.standardDeviation();
+
+ if (intervalFrameLengthMean < this.frameLengthDesiredThreshold && this._intervalFrameLengthEstimator.cdf(this.frameLengthDesiredThreshold) > .9) {
+ this._possibleMinimumComplexity = Math.max(this._possibleMinimumComplexity, currentComplexity);
+ } else if (intervalFrameLengthStandardDeviation > 2) {
+ // In the case where we might have found a previous interval where 60fps was reached. We hit a significant blip,
+ // so we should resample this area in the next ramp.
+ this._possibleMinimumComplexity = 1;
+ }
+ if (intervalFrameLengthMean - intervalFrameLengthStandardDeviation > this.frameLengthRampLowerThreshold)
+ this._possibleMaximumComplexity = Math.min(this._possibleMaximumComplexity, currentComplexity);
+ this._intervalFrameLengthEstimator.reset();
+
+ var progress = (timestamp - this._rampStartTimestamp) / this._currentRampLength;
+
+ if (progress < 1) {
+ // Reframe progress percentage so that the last interval of the ramp can sample at minimum complexity
+ progress = (timestamp - this._rampStartTimestamp) / (this._currentRampLength - this.intervalSamplingLength);
+ stage.tune(Math.max(this._minimumComplexity, Math.floor(Utilities.lerp(progress, this._maximumComplexity, this._minimumComplexity))) - currentComplexity);
+ return;
+ }
+
+ var regression = new Regression(this._sampler.samples, this._getComplexity, this._getFrameLength,
+ this._sampler.sampleCount - 1, this._rampStartIndex, { desiredFrameLength: this.frameLengthDesired });
+ this._rampRegressions.push(regression);
+
+ var frameLengthAtMaxComplexity = regression.valueAt(this._maximumComplexity);
+ if (frameLengthAtMaxComplexity < this.frameLengthRampLowerThreshold)
+ this._possibleMaximumComplexity = Math.floor(Utilities.lerp(Utilities.progressValue(this.frameLengthRampLowerThreshold, frameLengthAtMaxComplexity, this._lastTierFrameLength), this._maximumComplexity, this._lastTierComplexity));
+ // If the regression doesn't fit the first segment at all, keep the minimum bound at 1
+ if ((timestamp - this._sampler.samples[0][this._sampler.sampleCount - regression.n1]) / this._currentRampLength < .25)
+ this._possibleMinimumComplexity = 1;
+
+ this._minimumComplexityEstimator.sample(this._possibleMinimumComplexity);
+ this._minimumComplexity = Math.round(this._minimumComplexityEstimator.mean());
+
+ if (frameLengthAtMaxComplexity < this.frameLengthRampUpperThreshold) {
+ this._changePointEstimator.sample(regression.complexity);
+ // Ideally we'll target the change point in the middle of the ramp. If the range of the ramp is too small, there isn't enough
+ // range along the complexity (x) axis for a good regression calculation to be made, so force at least a range of 5
+ // particles. Make it possible to increase the maximum complexity in case unexpected noise caps the regression too low.
+ this._maximumComplexity = Math.round(this._minimumComplexity +
+ Math.max(5,
+ this._possibleMaximumComplexity - this._minimumComplexity,
+ (this._changePointEstimator.mean() - this._minimumComplexity) * 2));
+ } else {
+ // The slowest samples weighed the regression too heavily
+ this._maximumComplexity = Math.max(Math.round(.8 * this._maximumComplexity), this._minimumComplexity + 5);
+ }
+
+ // Next ramp
+ stage.tune(this._maximumComplexity - stage.complexity());
+ this._rampDidWarmup = false;
+ // Start timestamp represents start of ramp iteration and warm up
+ this._rampStartTimestamp = timestamp;
+ this._possibleMinimumComplexity = 1;
+ this._possibleMaximumComplexity = this._maximumComplexity;
+ },
+
+ _getComplexity: function(samples, i) {
+ return samples[1][i];
+ },
+
+ _getFrameLength: function(samples, i) {
+ return samples[0][i] - samples[0][i - 1];
+ },
+
+ processSamples: function(results)
+ {
+ Controller.prototype.processSamples.call(this, results);
+
+ // Have samplingTimeOffset represent time 0
+ var startTimestamp = this._marks[Strings.json.samplingStartTimeOffset].time;
+
+ for (var markName in results[Strings.json.marks]) {
+ results[Strings.json.marks][markName].time -= startTimestamp;
+ }
+
+ var controllerSamples = results[Strings.json.samples][Strings.json.controller];
+ controllerSamples.forEach(function(timeSample) {
+ controllerSamples.setFieldInDatum(timeSample, Strings.json.time, controllerSamples.getFieldInDatum(timeSample, Strings.json.time) - startTimestamp);
+ });
+
+ // Aggregate all of the ramps into one big complexity-frameLength dataset
+ var complexitySamples = new SampleData(controllerSamples.fieldMap);
+ results[Strings.json.samples][Strings.json.complexity] = complexitySamples;
+
+ results[Strings.json.controller] = [];
+ this._rampRegressions.forEach(function(ramp) {
+ var startIndex = ramp.startIndex, endIndex = ramp.endIndex;
+ var startTime = controllerSamples.getFieldInDatum(startIndex, Strings.json.time);
+ var endTime = controllerSamples.getFieldInDatum(endIndex, Strings.json.time);
+ var startComplexity = controllerSamples.getFieldInDatum(startIndex, Strings.json.complexity);
+ var endComplexity = controllerSamples.getFieldInDatum(endIndex, Strings.json.complexity);
+
+ var regression = {};
+ results[Strings.json.controller].push(regression);
+
+ var percentage = (ramp.complexity - startComplexity) / (endComplexity - startComplexity);
+ var inflectionTime = startTime + percentage * (endTime - startTime);
+
+ regression[Strings.json.regressions.segment1] = [
+ [startTime, ramp.s2 + ramp.t2 * startComplexity],
+ [inflectionTime, ramp.s2 + ramp.t2 * ramp.complexity]
+ ];
+ regression[Strings.json.regressions.segment2] = [
+ [inflectionTime, ramp.s1 + ramp.t1 * ramp.complexity],
+ [endTime, ramp.s1 + ramp.t1 * endComplexity]
+ ];
+ regression[Strings.json.complexity] = ramp.complexity;
+ regression[Strings.json.regressions.startIndex] = startIndex;
+ regression[Strings.json.regressions.endIndex] = endIndex;
+ regression[Strings.json.regressions.profile] = ramp.profile;
+
+ for (var j = startIndex; j <= endIndex; ++j)
+ complexitySamples.push(controllerSamples.at(j));
+ });
+
+ var complexityAverageSamples = new SampleData;
+ results[Strings.json.samples][Strings.json.complexityAverage] = complexityAverageSamples;
+ this._processComplexitySamples(complexitySamples, complexityAverageSamples);
+ }
+});
+
+Ramp30Controller = Utilities.createSubclass(RampController,
+ function(benchmark, options)
+ {
+ RampController.call(this, benchmark, options);
+ }, {
+
+ frameLengthDesired: 1000/30,
+ frameLengthDesiredThreshold: 1000/29,
+ frameLengthTierThreshold: 1000/20,
+ frameLengthRampLowerThreshold: 1000/20,
+ frameLengthRampUpperThreshold: 1000/12
+});
+
+Stage = Utilities.createClass(
+ function()
+ {
+ }, {
+
+ initialize: function(benchmark)
+ {
+ this._benchmark = benchmark;
+ this._element = document.getElementById("stage");
+ this._element.setAttribute("width", document.body.offsetWidth);
+ this._element.setAttribute("height", 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 "Not implemented";
+ },
+
+ animate: function()
+ {
+ throw "Not implemented";
+ },
+
+ clear: function()
+ {
+ return this.tune(-this.tune(0));
+ }
+});
+
+Utilities.extendObject(Stage, {
+ random: function(min, max)
+ {
+ return (Pseudo.random() * (max - min)) + min;
+ },
+
+ randomBool: function()
+ {
+ return !!Math.round(Pseudo.random());
+ },
+
+ randomSign: function()
+ {
+ return Pseudo.random() >= .5 ? 1 : -1;
+ },
+
+ randomInt: function(min, max)
+ {
+ return Math.floor(this.random(min, max + 1));
+ },
+
+ randomPosition: function(maxPosition)
+ {
+ return new Point(this.randomInt(0, maxPosition.x), this.randomInt(0, maxPosition.y));
+ },
+
+ randomSquareSize: function(min, max)
+ {
+ var side = this.random(min, max);
+ return new Point(side, side);
+ },
+
+ randomVelocity: function(maxVelocity)
+ {
+ return this.random(maxVelocity / 8, maxVelocity);
+ },
+
+ randomAngle: function()
+ {
+ return this.random(0, Math.PI * 2);
+ },
+
+ randomColor: function()
+ {
+ var min = 32;
+ var max = 256 - 32;
+ return "#"
+ + this.randomInt(min, max).toString(16)
+ + this.randomInt(min, max).toString(16)
+ + this.randomInt(min, max).toString(16);
+ },
+
+ randomStyleMixBlendMode: function()
+ {
+ var mixBlendModeList = [
+ 'normal',
+ 'multiply',
+ 'screen',
+ 'overlay',
+ 'darken',
+ 'lighten',
+ 'color-dodge',
+ 'color-burn',
+ 'hard-light',
+ 'soft-light',
+ 'difference',
+ 'exclusion',
+ 'hue',
+ 'saturation',
+ 'color',
+ 'luminosity'
+ ];
+
+ return mixBlendModeList[this.randomInt(0, mixBlendModeList.length)];
+ },
+
+ randomStyleFilter: function()
+ {
+ var filterList = [
+ 'grayscale(50%)',
+ 'sepia(50%)',
+ 'saturate(50%)',
+ 'hue-rotate(180)',
+ 'invert(50%)',
+ 'opacity(50%)',
+ 'brightness(50%)',
+ 'contrast(50%)',
+ 'blur(10px)',
+ 'drop-shadow(10px 10px 10px gray)'
+ ];
+
+ return filterList[this.randomInt(0, filterList.length)];
+ },
+
+ randomElementInArray: function(array)
+ {
+ return array[Stage.randomInt(0, array.length - 1)];
+ },
+
+ rotatingColor: function(cycleLengthMs, saturation, lightness)
+ {
+ return "hsl("
+ + Stage.dateFractionalValue(cycleLengthMs) * 360 + ", "
+ + ((saturation || .8) * 100).toFixed(0) + "%, "
+ + ((lightness || .35) * 100).toFixed(0) + "%)";
+ },
+
+ // Returns a fractional value that wraps around within [0,1]
+ dateFractionalValue: function(cycleLengthMs)
+ {
+ return (Date.now() / (cycleLengthMs || 2000)) % 1;
+ },
+
+ // Returns an increasing value slowed down by factor
+ dateCounterValue: function(factor)
+ {
+ return Date.now() / factor;
+ },
+
+ randomRotater: function()
+ {
+ return new Rotater(this.random(1000, 10000));
+ }
+});
+
+Rotater = Utilities.createClass(
+ function(rotateInterval)
+ {
+ this._timeDelta = 0;
+ this._rotateInterval = rotateInterval;
+ this._isSampling = false;
+ }, {
+
+ get interval()
+ {
+ return this._rotateInterval;
+ },
+
+ next: function(timeDelta)
+ {
+ this._timeDelta = (this._timeDelta + timeDelta) % this._rotateInterval;
+ },
+
+ degree: function()
+ {
+ return (360 * this._timeDelta) / this._rotateInterval;
+ },
+
+ rotateZ: function()
+ {
+ return "rotateZ(" + Math.floor(this.degree()) + "deg)";
+ },
+
+ rotate: function(center)
+ {
+ return "rotate(" + Math.floor(this.degree()) + ", " + center.x + "," + center.y + ")";
+ }
+});
+
+Benchmark = Utilities.createClass(
+ function(stage, options)
+ {
+ this._animateLoop = this._animateLoop.bind(this);
+
+ this._stage = stage;
+ this._stage.initialize(this, options);
+
+ switch (options["time-measurement"])
+ {
+ case "performance":
+ if (window.performance && window.performance.now)
+ this._getTimestamp = performance.now.bind(performance);
+ else
+ this._getTimestamp = null;
+ break;
+ case "raf":
+ this._getTimestamp = null;
+ break;
+ case "date":
+ this._getTimestamp = Date.now;
+ break;
+ }
+
+ options["test-interval"] *= 1000;
+ switch (options["controller"])
+ {
+ case "fixed":
+ this._controller = new FixedController(this, options);
+ break;
+ case "step":
+ this._controller = new StepController(this, options);
+ break;
+ case "adaptive":
+ this._controller = new AdaptiveController(this, options);
+ break;
+ case "ramp":
+ this._controller = new RampController(this, options);
+ break;
+ case "ramp30":
+ this._controller = new Ramp30Controller(this, options);
+ }
+ }, {
+
+ get stage()
+ {
+ return this._stage;
+ },
+
+ get timestamp()
+ {
+ return this._currentTimestamp - this._startTimestamp;
+ },
+
+ backgroundColor: function()
+ {
+ var stage = window.getComputedStyle(document.getElementById("stage"));
+ return stage["background-color"];
+ },
+
+ run: function()
+ {
+ return this.waitUntilReady().then(function() {
+ this._finishPromise = new SimplePromise;
+ this._previousTimestamp = undefined;
+ this._didWarmUp = false;
+ this._stage.tune(this._controller.initialComplexity - this._stage.complexity());
+ this._animateLoop();
+ return this._finishPromise;
+ }.bind(this));
+ },
+
+ // Subclasses should override this if they have setup to do prior to commencing.
+ waitUntilReady: function()
+ {
+ var promise = new SimplePromise;
+ promise.resolve();
+ return promise;
+ },
+
+ _animateLoop: function(timestamp)
+ {
+ timestamp = (this._getTimestamp && this._getTimestamp()) || timestamp;
+ this._currentTimestamp = timestamp;
+
+ if (this._controller.shouldStop(timestamp)) {
+ this._finishPromise.resolve(this._controller.results());
+ return;
+ }
+
+ if (!this._didWarmUp) {
+ if (!this._previousTimestamp)
+ this._previousTimestamp = timestamp;
+ else if (timestamp - this._previousTimestamp >= 100) {
+ this._didWarmUp = true;
+ this._startTimestamp = timestamp;
+ this._controller.start(timestamp, this._stage);
+ this._previousTimestamp = timestamp;
+ }
+
+ this._stage.animate(0);
+ requestAnimationFrame(this._animateLoop);
+ return;
+ }
+
+ this._controller.update(timestamp, this._stage);
+ this._stage.animate(timestamp - this._previousTimestamp);
+ this._previousTimestamp = timestamp;
+ requestAnimationFrame(this._animateLoop);
+ }
+});
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/resources/math.js b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/math.js
new file mode 100644
index 0000000000..9c2706e2a3
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/math.js
@@ -0,0 +1,268 @@
+SimpleKalmanEstimator = Utilities.createSubclass(Experiment,
+ function(processError, measurementError) {
+ Experiment.call(this, false);
+ var error = .5 * (Math.sqrt(processError * processError + 4 * processError * measurementError) - processError);
+ this._gain = error / (error + measurementError);
+ }, {
+
+ sample: function(newMeasurement)
+ {
+ if (!this._initialized) {
+ this._initialized = true;
+ this.estimate = newMeasurement;
+ return;
+ }
+
+ this.estimate = this.estimate + this._gain * (newMeasurement - this.estimate);
+ },
+
+ reset: function()
+ {
+ Experiment.prototype.reset.call(this);
+ this._initialized = false;
+ this.estimate = 0;
+ }
+});
+
+PIDController = Utilities.createClass(
+ function(ysp)
+ {
+ this._ysp = ysp;
+ this._out = 0;
+
+ this._Kp = 0;
+ this._stage = PIDController.stages.WARMING;
+
+ this._eold = 0;
+ this._I = 0;
+ }, {
+
+ // Determines whether the current y is
+ // before ysp => (below ysp if ysp > y0) || (above ysp if ysp < y0)
+ // after ysp => (above ysp if ysp > y0) || (below ysp if ysp < y0)
+ _yPosition: function(y)
+ {
+ return (y < this._ysp) == (this._y0 < this._ysp)
+ ? PIDController.yPositions.BEFORE_SETPOINT
+ : PIDController.yPositions.AFTER_SETPOINT;
+ },
+
+ // Calculate the ultimate distance from y0 after time t. We want to move very
+ // slowly at the beginning to see how adding few items to the test can affect
+ // its output. The complexity of a single item might be big enough to keep the
+ // proportional gain very small but achieves the desired progress. But if y does
+ // not change significantly after adding few items, that means we need a much
+ // bigger gain. So we need to move over a cubic curve which increases very
+ // slowly with small t values but moves very fast with larger t values.
+ // The basic formula is: y = t^3
+ // Change the formula to reach y=1 after 1000 ms: y = (t/1000)^3
+ // Change the formula to reach y=(ysp - y0) after 1000 ms: y = (ysp - y0) * (t/1000)^3
+ _distanceUltimate: function(t)
+ {
+ return (this._ysp - this._y0) * Math.pow(t / 1000, 3);
+ },
+
+ // Calculates the distance of y relative to y0. It also ensures we do not return
+ // zero by returning a epsilon value in the same direction as ultimate distance.
+ _distance: function(y, du)
+ {
+ const epsilon = 0.0001;
+ var d = y - this._y0;
+ return du < 0 ? Math.min(d, -epsilon) : Math.max(d, epsilon);
+ },
+
+ // Decides how much the proportional gain should be increased during the manual
+ // gain stage. We choose to use the ratio of the ultimate distance to the current
+ // distance as an indication of how much the system is responsive. We want
+ // to keep the increment under control so it does not cause the system instability
+ // So we choose to take the natural logarithm of this ratio.
+ _gainIncrement: function(t, y, e)
+ {
+ var du = this._distanceUltimate(t);
+ var d = this._distance(y, du);
+ return Math.log(du / d) * 0.1;
+ },
+
+ // Update the stage of the controller based on its current stage and the system output
+ _updateStage: function(y)
+ {
+ var yPosition = this._yPosition(y);
+
+ switch (this._stage) {
+ case PIDController.stages.WARMING:
+ if (yPosition == PIDController.yPositions.AFTER_SETPOINT)
+ this._stage = PIDController.stages.OVERSHOOT;
+ break;
+
+ case PIDController.stages.OVERSHOOT:
+ if (yPosition == PIDController.yPositions.BEFORE_SETPOINT)
+ this._stage = PIDController.stages.UNDERSHOOT;
+ break;
+
+ case PIDController.stages.UNDERSHOOT:
+ if (yPosition == PIDController.yPositions.AFTER_SETPOINT)
+ this._stage = PIDController.stages.SATURATE;
+ break;
+ }
+ },
+
+ // Manual tuning is used before calculating the PID controller gains.
+ _tuneP: function(e)
+ {
+ // The output is the proportional term only.
+ return this._Kp * e;
+ },
+
+ // PID tuning function. Kp, Ti and Td were already calculated
+ _tunePID: function(h, y, e)
+ {
+ // Proportional term.
+ var P = this._Kp * e;
+
+ // Integral term is the area under the curve starting from the beginning
+ // till the current time.
+ this._I += (this._Kp / this._Ti) * ((e + this._eold) / 2) * h;
+
+ // Derivative term is the slope of the curve at the current time.
+ var D = (this._Kp * this._Td) * (e - this._eold) / h;
+
+ // The ouput is a PID function.
+ return P + this._I + D;
+ },
+
+ // Apply different strategies for the tuning based on the stage of the controller.
+ _tune: function(t, h, y, e)
+ {
+ switch (this._stage) {
+ case PIDController.stages.WARMING:
+ // This is the first stage of the Zieglerâ€Nichols method. It increments
+ // the proportional gain till the system output passes the set-point value.
+ if (typeof this._y0 == "undefined") {
+ // This is the first time a tuning value is required. We want the test
+ // to add only one item. So we need to return -1 which forces us to
+ // choose the initial value of Kp to be = -1 / e
+ this._y0 = y;
+ this._Kp = -1 / e;
+ } else {
+ // Keep incrementing the Kp as long as we have not reached the
+ // set-point yet
+ this._Kp += this._gainIncrement(t, y, e);
+ }
+
+ return this._tuneP(e);
+
+ case PIDController.stages.OVERSHOOT:
+ // This is the second stage of the Zieglerâ€Nichols method. It measures the
+ // oscillation period.
+ if (typeof this._t0 == "undefined") {
+ // t is the time of the begining of the first overshot
+ this._t0 = t;
+ this._Kp /= 2;
+ }
+
+ return this._tuneP(e);
+
+ case PIDController.stages.UNDERSHOOT:
+ // This is the end of the Zieglerâ€Nichols method. We need to calculate the
+ // integral and derivative periods.
+ if (typeof this._Ti == "undefined") {
+ // t is the time of the end of the first overshot
+ var Tu = t - this._t0;
+
+ // Calculate the system parameters from Kp and Tu assuming
+ // a "some overshoot" control type. See:
+ // https://en.wikipedia.org/wiki/Ziegler%E2%80%93Nichols_method
+ this._Ti = Tu / 2;
+ this._Td = Tu / 3;
+ this._Kp = 0.33 * this._Kp;
+
+ // Calculate the tracking time.
+ this._Tt = Math.sqrt(this._Ti * this._Td);
+ }
+
+ return this._tunePID(h, y, e);
+
+ case PIDController.stages.SATURATE:
+ return this._tunePID(h, y, e);
+ }
+
+ return 0;
+ },
+
+ // Ensures the system does not fluctuates.
+ _saturate: function(v, e)
+ {
+ var u = v;
+
+ switch (this._stage) {
+ case PIDController.stages.OVERSHOOT:
+ case PIDController.stages.UNDERSHOOT:
+ // Calculate the min-max values of the saturation actuator.
+ if (typeof this._min == "undefined")
+ this._min = this._max = this._out;
+ else {
+ this._min = Math.min(this._min, this._out);
+ this._max = Math.max(this._max, this._out);
+ }
+ break;
+
+ case PIDController.stages.SATURATE:
+ const limitPercentage = 0.90;
+ var min = this._min > 0 ? Math.min(this._min, this._max * limitPercentage) : this._min;
+ var max = this._max < 0 ? Math.max(this._max, this._min * limitPercentage) : this._max;
+ var out = this._out + u;
+
+ // Clip the controller output to the min-max values
+ out = Math.max(Math.min(max, out), min);
+ u = out - this._out;
+
+ // Apply the back-calculation and tracking
+ if (u != v)
+ u += (this._Kp * this._Tt / this._Ti) * e;
+ break;
+ }
+
+ this._out += u;
+ return u;
+ },
+
+ // Called from the benchmark to tune its test. It uses Ziegler-Nichols method
+ // to calculate the controller parameters. It then returns a PID tuning value.
+ tune: function(t, h, y)
+ {
+ this._updateStage(y);
+
+ // Current error.
+ var e = this._ysp - y;
+ var v = this._tune(t, h, y, e);
+
+ // Save e for the next call.
+ this._eold = e;
+
+ // Apply back-calculation and tracking to avoid integrator windup
+ return this._saturate(v, e);
+ }
+});
+
+Utilities.extendObject(PIDController, {
+ // This enum will be used to tell whether the system output (or the controller input)
+ // is moving towards the set-point or away from it.
+ yPositions: {
+ BEFORE_SETPOINT: 0,
+ AFTER_SETPOINT: 1
+ },
+
+ // The Ziegler-Nichols method for is used tuning the PID controller. The workflow of
+ // the tuning is split into four stages. The first two stages determine the values
+ // of the PID controller gains. During these two stages we return the proportional
+ // term only. The third stage is used to determine the min-max values of the
+ // saturation actuator. In the last stage back-calculation and tracking are applied
+ // to avoid integrator windup. During the last two stages, we return a PID control
+ // value.
+ stages: {
+ WARMING: 0, // Increase the value of the Kp until the system output reaches ysp.
+ OVERSHOOT: 1, // Measure the oscillation period and the overshoot value
+ UNDERSHOOT: 2, // Return PID value and measure the undershoot value
+ SATURATE: 3 // Return PID value and apply back-calculation and tracking.
+ }
+});
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/resources/stage.css b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/stage.css
new file mode 100644
index 0000000000..0b6ffdc4a2
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/stage.css
@@ -0,0 +1,27 @@
+html {
+ height: 100%;
+}
+body {
+ width: 100%;
+ height: 100%;
+ margin: 0;
+ padding: 0;
+ background-color: rgb(241, 241, 241);
+ font-family: "Helvetica Neue", Helvetica, Verdana, sans-serif;
+}
+
+#stage {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ background-color: rgb(241, 241, 241);
+ overflow: hidden;
+}
+
+#center-text {
+ position: absolute;
+ z-index: 3;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+}
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/resources/star.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/star.svg
new file mode 100644
index 0000000000..3c46ae0419
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/star.svg
@@ -0,0 +1,8 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1 1">
+ <defs>
+ <mask id="star-mask" maskUnits="objectBoundingBox" maskContentUnits="objectBoundingBox">
+ <path fill="white" d="M.50,0L.38,.38L0,.38L.30,.60L.18,1L.50,.75L.82,1L.70,.60L1,.38L.62,.38z" />
+ </mask>
+ </defs>
+ <path d="M.50,0L.38,.38L0,.38L.30,.60L.18,1L.50,.75L.82,1L.70,.60L1,.38L.62,.38z" fill="white" />
+</svg>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/resources/yin-yang.png b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/yin-yang.png
new file mode 100644
index 0000000000..3162f6ec00
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/yin-yang.png
Binary files differ
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/resources/yin-yang.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/yin-yang.svg
new file mode 100644
index 0000000000..4412626774
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/yin-yang.svg
@@ -0,0 +1,17 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 200 200">
+ <defs>
+ <clipPath id="left-half">
+ <rect width="100" height="200"/>
+ </clipPath>
+ <clipPath id="right-half">
+ <rect x="100" width="100" height="200"/>
+ </clipPath>
+ </defs>
+ <circle cx="100" cy="100" r="98" fill="none" stroke="green" stroke-width="2"/>
+ <circle cx="100" cy="100" r="98" fill="white" clip-path="url(#left-half)"/>
+ <circle cx="100" cy="100" r="98" fill="green" clip-path="url(#right-half)"/>
+ <circle cx="100" cy="50" r="49" fill="green"/>
+ <circle cx="100" cy="148" r="49" fill="white"/>
+ <circle cx="100" cy="50" r="10" fill="white"/>
+ <circle cx="100" cy="148" r="10" fill="green"/>
+</svg>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/simple/resources/simple-canvas-paths.js b/third_party/webkit/PerformanceTests/MotionMark/tests/simple/resources/simple-canvas-paths.js
new file mode 100644
index 0000000000..cda985b221
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/simple/resources/simple-canvas-paths.js
@@ -0,0 +1,453 @@
+(function() {
+
+// === PAINT OBJECTS ===
+
+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);
+
+ this._point1 = center.add(delta);
+ this._point2 = center.subtract(delta);
+ this._color = Stage.randomColor();
+ this._lineWidth = Stage.randomInt(1, 100);
+ }, {
+
+ 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();
+ }
+});
+
+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));
+ }, {
+
+ draw: function(context) {
+ context.lineTo(this._point.x, this._point.y);
+ }
+})
+
+CanvasQuadraticSegment = Utilities.createClass(
+ function(stage) {
+ var maxSize = Stage.randomInt(20, 200);
+ var toCenter = Stage.randomPosition(stage.size).subtract(new Point(maxSize/2, maxSize/2));
+
+ 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);
+ }, {
+
+ 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();
+ }
+});
+
+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));
+ }, {
+
+ draw: function(context) {
+ context.quadraticCurveTo(this._point1.x, this._point1.y, this._point2.x, this._point2.y);
+ }
+});
+
+CanvasBezierSegment = Utilities.createClass(
+ function(stage) {
+ var maxSize = Stage.randomInt(20, 200);
+ var toCenter = Stage.randomPosition(stage.size).subtract(new Point(maxSize/2, maxSize/2));
+
+ 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);
+ }, {
+
+ 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();
+ }
+});
+
+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));
+ }, {
+
+ draw: function(context) {
+ context.bezierCurveTo(this._point1.x, this._point1.y, this._point2.x, this._point2.y, this._point3.x, this._point3.y);
+ }
+});
+
+CanvasArcToSegment = Utilities.createClass(
+ function(stage) {
+ var maxSize = Stage.randomInt(20, 200);
+ var toCenter = Stage.randomPosition(stage.size).subtract(new Point(maxSize/2, maxSize/2));
+
+ 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);
+ }, {
+
+ 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();
+ }
+});
+
+CanvasEllipse = Utilities.createClass(
+ function(stage) {
+ this._radius = new Point(Stage.randomInt(20, 200), Stage.randomInt(20, 200));
+ var toCenter = Stage.randomPosition(stage.size).subtract(this._radius.multiply(.5));
+
+ this._center = Stage.randomPosition(this._radius).add(toCenter);
+ this._rotation = Stage.randomAngle();
+ this._startAngle = Stage.randomAngle();
+ this._endAngle = Stage.randomAngle();
+ this._anticlockwise = Stage.randomBool();
+ this._color = Stage.randomColor();
+ this._lineWidth = Stage.randomInt(1, 20);
+ }, {
+
+ draw: function(context) {
+ context.strokeStyle = this._color;
+ context.lineWidth = this._lineWidth;
+ context.beginPath();
+ context.ellipse(this._center.x, this._center.y, this._radius.width, this._radius.height, this._rotation, this._startAngle, this._endAngle, this._anticlockwise);
+ context.stroke();
+ }
+});
+
+CanvasEllipseFill = Utilities.createClass(
+ function(stage) {
+ CanvasEllipse.call(this, stage);
+ }, {
+
+ draw: function(context) {
+ context.fillStyle = this._color;
+ context.beginPath();
+ context.ellipse(this._center.x, this._center.y, this._radius.width, this._radius.height, this._rotation, this._startAngle, this._endAngle, this._anticlockwise);
+ context.fill();
+ }
+});
+
+CanvasStroke = Utilities.createClass(
+ function (stage) {
+ this._object = new (Stage.randomElementInArray(this.objectTypes))(stage);
+ }, {
+
+ objectTypes: [
+ CanvasQuadraticSegment,
+ CanvasBezierSegment,
+ CanvasArcToSegment,
+ CanvasArcSegment,
+ CanvasRect,
+ CanvasEllipse
+ ],
+
+ draw: function(context) {
+ this._object.draw(context);
+ }
+});
+
+CanvasFill = Utilities.createClass(
+ function (stage) {
+ this._object = new (Stage.randomElementInArray(this.objectTypes))(stage);
+ }, {
+
+ objectTypes: [
+ CanvasArcToSegmentFill,
+ CanvasArcSegmentFill,
+ CanvasRectFill,
+ CanvasEllipseFill
+ ],
+
+ draw: function(context) {
+ this._object.draw(context);
+ }
+});
+
+// === STAGES ===
+
+SimpleCanvasPathStrokeStage = Utilities.createSubclass(SimpleCanvasStage,
+ function(canvasObject) {
+ SimpleCanvasStage.call(this, canvasObject);
+ }, {
+
+ animate: function()
+ {
+ var context = this.context;
+ context.clearRect(0, 0, this.size.x, this.size.y);
+ context.lineWidth = Stage.randomInt(1, 20);
+ context.strokeStyle = Stage.rotatingColor();
+ context.beginPath();
+ context.moveTo(this.size.x / 2, this.size.y / 2);
+ for (var i = 0, length = this.offsetIndex; i < length; ++i)
+ this.objects[i].draw(context);
+ context.stroke();
+ }
+});
+
+SimpleCanvasPathFillStage = Utilities.createSubclass(SimpleCanvasStage,
+ function(canvasObject) {
+ SimpleCanvasStage.call(this, canvasObject);
+ }, {
+
+ animate: function()
+ {
+ var context = this.context;
+ context.clearRect(0, 0, this.size.x, this.size.y);
+ context.fillStyle = Stage.rotatingColor();
+ context.beginPath();
+ context.moveTo(this.size.x / 2, this.size.y / 2);
+ for (var i = 0, length = this.offsetIndex; i < length; ++i)
+ this.objects[i].draw(context);
+ context.fill();
+ }
+});
+
+CanvasLineSegmentStage = Utilities.createSubclass(SimpleCanvasStage,
+ function()
+ {
+ SimpleCanvasStage.call(this, CanvasLineSegment);
+ }, {
+
+ initialize: function(benchmark, options)
+ {
+ SimpleCanvasStage.prototype.initialize.call(this, benchmark, options);
+ this.context.lineCap = options["lineCap"] || "butt";
+ }
+});
+
+CanvasLinePathStage = Utilities.createSubclass(SimpleCanvasPathStrokeStage,
+ function()
+ {
+ SimpleCanvasPathStrokeStage.call(this, CanvasLinePoint);
+ }, {
+
+ initialize: function(benchmark, options)
+ {
+ SimpleCanvasPathStrokeStage.prototype.initialize.call(this, benchmark, options);
+ this.context.lineJoin = options["lineJoin"] || "bevel";
+ }
+});
+
+CanvasLineDashStage = Utilities.createSubclass(SimpleCanvasStage,
+ function()
+ {
+ SimpleCanvasStage.call(this, CanvasLinePoint);
+ this._step = 0;
+ }, {
+
+ initialize: function(benchmark, options)
+ {
+ SimpleCanvasStage.prototype.initialize.call(this, benchmark, options);
+ this.context.setLineDash([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+ this.context.lineWidth = 1;
+ this.context.strokeStyle = "#000";
+ },
+
+ animate: function()
+ {
+ var context = this.context;
+ context.clearRect(0, 0, this.size.x, this.size.y);
+ context.lineDashOffset = this._step++;
+ context.beginPath();
+ context.moveTo(this.size.x / 2, this.size.y / 2);
+ for (var i = 0, length = this.offsetIndex; i < length; ++i)
+ this.objects[i].draw(context);
+ context.stroke();
+ }
+});
+
+// === BENCHMARK ===
+
+CanvasPathBenchmark = Utilities.createSubclass(Benchmark,
+ function(options)
+ {
+ var stage;
+ switch (options["pathType"]) {
+ case "line":
+ stage = new CanvasLineSegmentStage();
+ break;
+ case "linePath": {
+ if ("lineJoin" in options)
+ stage = new CanvasLinePathStage();
+ if ("lineDash" in options)
+ stage = new CanvasLineDashStage();
+ break;
+ }
+ case "quadratic":
+ stage = new SimpleCanvasStage(CanvasQuadraticSegment);
+ break;
+ case "quadraticPath":
+ stage = new SimpleCanvasPathStrokeStage(CanvasQuadraticPoint);
+ break;
+ case "bezier":
+ stage = new SimpleCanvasStage(CanvasBezierSegment);
+ break;
+ case "bezierPath":
+ stage = new SimpleCanvasPathStrokeStage(CanvasBezierPoint);
+ break;
+ case "arcTo":
+ stage = new SimpleCanvasStage(CanvasArcToSegment);
+ break;
+ case "arc":
+ stage = new SimpleCanvasStage(CanvasArcSegment);
+ break;
+ case "rect":
+ stage = new SimpleCanvasStage(CanvasRect);
+ break;
+ case "ellipse":
+ stage = new SimpleCanvasStage(CanvasEllipse);
+ break;
+ case "lineFill":
+ stage = new SimpleCanvasPathFillStage(CanvasLinePoint);
+ break;
+ case "quadraticFill":
+ stage = new SimpleCanvasPathFillStage(CanvasQuadraticPoint);
+ break;
+ case "bezierFill":
+ stage = new SimpleCanvasPathFillStage(CanvasBezierPoint);
+ break;
+ case "arcToFill":
+ stage = new SimpleCanvasStage(CanvasArcToSegmentFill);
+ break;
+ case "arcFill":
+ stage = new SimpleCanvasStage(CanvasArcSegmentFill);
+ break;
+ case "rectFill":
+ stage = new SimpleCanvasStage(CanvasRectFill);
+ break;
+ case "ellipseFill":
+ stage = new SimpleCanvasStage(CanvasEllipseFill);
+ break;
+ case "strokes":
+ stage = new SimpleCanvasStage(CanvasStroke);
+ break;
+ case "fills":
+ stage = new SimpleCanvasStage(CanvasFill);
+ break;
+ }
+
+ Benchmark.call(this, stage, options);
+ }
+);
+
+window.benchmarkClass = CanvasPathBenchmark;
+
+})(); \ No newline at end of file
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/simple/resources/simple-canvas.js b/third_party/webkit/PerformanceTests/MotionMark/tests/simple/resources/simple-canvas.js
new file mode 100644
index 0000000000..483d535d75
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/simple/resources/simple-canvas.js
@@ -0,0 +1,35 @@
+Utilities.extendObject(SimpleCanvasStage.prototype, {
+ tune: function(count)
+ {
+ if (count == 0)
+ return;
+
+ if (count < 0) {
+ this.offsetIndex = Math.max(this.offsetIndex + count, 0);
+ return;
+ }
+
+ this.offsetIndex = this.offsetIndex + count;
+ if (this.offsetIndex > this.objects.length) {
+ // For some tests, it may be easier to see how well the test is going
+ // by limiting the range of coordinates in which new objects can reside
+ var coordinateMaximumFactor = Math.min(this.objects.length, Math.min(this.size.x, this.size.y)) / Math.min(this.size.x, this.size.y);
+ var newIndex = this.offsetIndex - this.objects.length;
+ for (var i = 0; i < newIndex; ++i)
+ this.objects.push(new this._canvasObject(this, coordinateMaximumFactor));
+ }
+ },
+
+ animate: function()
+ {
+ var context = this.context;
+ context.clearRect(0, 0, this.size.x, this.size.y);
+ for (var i = 0, length = this.offsetIndex; i < length; ++i)
+ this.objects[i].draw(context);
+ },
+
+ complexity: function()
+ {
+ return this.offsetIndex;
+ }
+});
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/simple/resources/tiled-canvas-image.js b/third_party/webkit/PerformanceTests/MotionMark/tests/simple/resources/tiled-canvas-image.js
new file mode 100644
index 0000000000..f5d02b68a4
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/simple/resources/tiled-canvas-image.js
@@ -0,0 +1,119 @@
+(function() {
+
+CanvasImageTile = Utilities.createClass(
+ function(stage, source)
+ {
+ this._context = stage.context;
+ this._size = stage.tileSize;
+ this.source = source;
+ }, {
+
+ getImageData: function()
+ {
+ this._imagedata = this._context.getImageData(this.source.x, this.source.y, this._size.width, this._size.height);
+ },
+
+ putImageData: function(destination)
+ {
+ this._context.putImageData(this._imagedata, destination.x, destination.y);
+ }
+});
+
+TiledCanvasImageStage = Utilities.createSubclass(Stage,
+ function(element, options)
+ {
+ Stage.call(this);
+ }, {
+
+ initialize: function(benchmark, options)
+ {
+ Stage.prototype.initialize.call(this, benchmark, options);
+ this.context = this.element.getContext("2d");
+ this._setupTiles();
+ },
+
+ _setupTiles: function()
+ {
+ const maxTilesPerRow = 50;
+ const maxTilesPerCol = 50;
+
+ this.tileSize = this.size.multiply(new Point(1 / maxTilesPerRow, 1 / maxTilesPerCol));
+
+ this._tiles = new Array(maxTilesPerRow * maxTilesPerCol);
+
+ var source = Point.zero;
+ for (var index = 0; index < this._tiles.length; ++index) {
+ this._tiles[index] = new CanvasImageTile(this, source);
+ source = this._nextTilePosition(source);
+ }
+
+ this._ctiles = 0;
+ },
+
+ _nextTilePosition: function(destination)
+ {
+ var next = destination.add(this.tileSize);
+
+ if (next.x >= this._size.width)
+ return new Point(0, next.y >= this._size.height ? 0 : next.y);
+
+ return new Point(next.x, destination.y);
+ },
+
+ tune: function(count)
+ {
+ this._ctiles += count;
+
+ this._ctiles = Math.max(this._ctiles, 0);
+ this._ctiles = Math.min(this._ctiles, this._tiles.length);
+ },
+
+ _drawBackground: function()
+ {
+ var size = this._benchmark._stage.size;
+ var gradient = this.context.createLinearGradient(0, 0, size.width, 0);
+ gradient.addColorStop(0, "red");
+ gradient.addColorStop(1, "white");
+ this.context.save();
+ this.context.fillStyle = gradient;
+ this.context.fillRect(0, 0, size.width, size.height);
+ this.context.restore();
+ },
+
+ animate: function(timeDelta)
+ {
+ this._drawBackground();
+
+ if (!this._ctiles)
+ return;
+
+ this._tiles.shuffle();
+
+ var destinations = new Array(this._ctiles);
+ for (var index = 0; index < this._ctiles; ++index) {
+ this._tiles[index].getImageData();
+ destinations[index] = this._tiles[index].source;
+ }
+
+ destinations.shuffle();
+
+ for (var index = 0; index < this._ctiles; ++index)
+ this._tiles[index].putImageData(destinations[index]);
+ },
+
+ complexity: function()
+ {
+ return this._ctiles;
+ }
+});
+
+TiledCanvasImageBenchmark = Utilities.createSubclass(Benchmark,
+ function(options)
+ {
+ Benchmark.call(this, new TiledCanvasImageStage(), options);
+ }
+);
+
+window.benchmarkClass = TiledCanvasImageBenchmark;
+
+})();
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/simple/simple-canvas-paths.html b/third_party/webkit/PerformanceTests/MotionMark/tests/simple/simple-canvas-paths.html
new file mode 100644
index 0000000000..5bb69bc54f
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/simple/simple-canvas-paths.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="../resources/stage.css">
+</head>
+<body>
+ <canvas id="stage"></canvas>
+ <script src="../../resources/strings.js"></script>
+ <script src="../../resources/extensions.js"></script>
+ <script src="../../resources/statistics.js"></script>
+ <script src="../resources/math.js"></script>
+ <script src="../resources/main.js"></script>
+ <script src="../master/resources/canvas-stage.js"></script>
+ <script src="resources/simple-canvas.js"></script>
+ <script src="resources/simple-canvas-paths.js"></script>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/simple/tiled-canvas-image.html b/third_party/webkit/PerformanceTests/MotionMark/tests/simple/tiled-canvas-image.html
new file mode 100644
index 0000000000..c7c0fef774
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/simple/tiled-canvas-image.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="../resources/stage.css">
+</head>
+<body>
+ <canvas id="stage"></canvas>
+ <script src="../../resources/strings.js"></script>
+ <script src="../../resources/extensions.js"></script>
+ <script src="../../resources/statistics.js"></script>
+ <script src="../resources/math.js"></script>
+ <script src="../resources/main.js"></script>
+ <script src="resources/tiled-canvas-image.js"></script>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/template/resources/template-canvas.js b/third_party/webkit/PerformanceTests/MotionMark/tests/template/resources/template-canvas.js
new file mode 100644
index 0000000000..b74984c010
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/template/resources/template-canvas.js
@@ -0,0 +1,89 @@
+(function() {
+
+function TemplateCanvasObject(stage)
+{
+ // For the canvas stage, most likely you will need to create your
+ // animated object since it's only draw time thing.
+
+ // Fill in your object data.
+}
+
+TemplateCanvasObject.prototype = {
+ _draw: function()
+ {
+ // Draw your object.
+ },
+
+ animate: function(timeDelta)
+ {
+ // Redraw the animated object. The last time this animated
+ // item was drawn before 'timeDelta'.
+
+ // Move your object.
+
+ // Redraw your object.
+ this._draw();
+ }
+};
+
+TemplateCanvasStage = Utilities.createSubclass(Stage,
+ function()
+ {
+ Stage.call(this);
+ }, {
+
+ initialize: function(benchmark, options)
+ {
+ Stage.prototype.initialize.call(this, benchmark, options);
+ this.context = this.element.getContext("2d");
+
+ // Define a collection for your objects.
+ },
+
+ tune: function(count)
+ {
+ // If count is -ve, -count elements need to be removed form the
+ // stage. If count is +ve, +count elements need to be added to
+ // the stage.
+
+ // Change objects in the stage.
+ },
+
+ animate: function(timeDelta)
+ {
+ // Animate the elements such that all of them are redrawn. Most
+ // likely you will need to call TemplateCanvasObject.animate()
+ // for all your animated objects here.
+
+ // Most likely you will need to clear the canvas with every redraw.
+ this.context.clearRect(0, 0, this.size.x, this.size.y);
+
+ // Loop through all your objects and ask them to animate.
+ }
+});
+
+TemplateCanvasBenchmark = Utilities.createSubclass(Benchmark,
+ function(options)
+ {
+ Benchmark.call(this, new TemplateCanvasStage(), options);
+ }, {
+
+ // Override this function if the benchmark needs to wait for resources to be
+ // loaded.
+ //
+ // Default implementation returns a resolved promise, so that the benchmark
+ // benchmark starts right away. Here's an example where we're waiting 5
+ // seconds before starting the benchmark.
+ waitUntilReady: function()
+ {
+ var promise = new SimplePromise;
+ window.setTimeout(function() {
+ promise.resolve();
+ }, 5000);
+ return promise;
+ }
+});
+
+window.benchmarkClass = TemplateCanvasBenchmark;
+
+})(); \ No newline at end of file
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/template/resources/template-css.js b/third_party/webkit/PerformanceTests/MotionMark/tests/template/resources/template-css.js
new file mode 100644
index 0000000000..cdaa814af0
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/template/resources/template-css.js
@@ -0,0 +1,46 @@
+(function() {
+
+TemplateCssStage = Utilities.createSubclass(Stage,
+ function()
+ {
+ Stage.call(this);
+ }, {
+
+ initialize: function(benchmark, options)
+ {
+ Stage.prototype.initialize.call(this, benchmark, options);
+
+ // Do initialization here.
+ },
+
+ tune: function(count)
+ {
+ // If count is -ve, -count elements need to be removed form the
+ // stage. If count is +ve, +count elements need to be added to
+ // the stage.
+
+ // Change objects in the stage.
+ },
+
+ animate: function(timeDelta)
+ {
+ // Animate the elements such that all of them are redrawn. You
+ // may need to define your object so it keeps its animation data.
+ // This object should encapsulate a corrosponding HTMLElement.
+ // You may also define a method called animate() in this object
+ // and just call this function here for all the elements.
+
+ // Loop through all your objects and ask them to animate.
+ }
+});
+
+TemplateCssBenchmark = Utilities.createSubclass(Benchmark,
+ function(options)
+ {
+ Benchmark.call(this, new TemplateCssStage(), options);
+ }
+);
+
+window.benchmarkClass = TemplateCssBenchmark;
+
+})();
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/template/resources/template-svg.js b/third_party/webkit/PerformanceTests/MotionMark/tests/template/resources/template-svg.js
new file mode 100644
index 0000000000..8fee9c3478
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/template/resources/template-svg.js
@@ -0,0 +1,46 @@
+(function() {
+
+TemplateSvgStage = Utilities.createSubclass(Stage,
+ function()
+ {
+ Stage.call(this);
+ }, {
+
+ initialize: function(benchmark, options)
+ {
+ Stage.prototype.initialize.call(this, benchmark, options);
+
+ // Do initialization here.
+ },
+
+ tune: function(count)
+ {
+ // If count is -ve, -count elements need to be removed form the
+ // stage. If count is +ve, +count elements need to be added to
+ // the stage.
+
+ // TODO: Change objects in the stage.
+ },
+
+ animate: function(timeDelta)
+ {
+ // Animate the elements such that all of them are redrawn. You
+ // may need to define your object so it keeps its animation data.
+ // This object should encapsulate a corrosponding SVGElement.
+ // You may also define a method called animate() in this object
+ // and just call this function here for all the elements.
+
+ // TODO: Loop through all your objects and ask them to animate.
+ }
+});
+
+TemplateSvgBenchmark = Utilities.createSubclass(Benchmark,
+ function(options)
+ {
+ Benchmark.call(this, new TemplateSvgStage(), options);
+ }
+);
+
+window.benchmarkClass = TemplateSvgBenchmark;
+
+})();
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/template/template-canvas.html b/third_party/webkit/PerformanceTests/MotionMark/tests/template/template-canvas.html
new file mode 100644
index 0000000000..dcb7f52861
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/template/template-canvas.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="../resources/stage.css">
+</head>
+<body>
+ <canvas id="stage"></canvas>
+ <script src="../../resources/strings.js"></script>
+ <script src="../../resources/extensions.js"></script>
+ <script src="../../resources/statistics.js"></script>
+ <script src="../resources/math.js"></script>
+ <script src="../resources/main.js"></script>
+ <script src="resources/template-canvas.js"></script>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/template/template-css.html b/third_party/webkit/PerformanceTests/MotionMark/tests/template/template-css.html
new file mode 100644
index 0000000000..70eb214e95
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/template/template-css.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="../resources/stage.css">
+</head>
+<body>
+ <div id="stage"></div>
+ <script src="../../resources/strings.js"></script>
+ <script src="../../resources/extensions.js"></script>
+ <script src="../../resources/statistics.js"></script>
+ <script src="../resources/math.js"></script>
+ <script src="../resources/main.js"></script>
+ <script src="resources/template-css.js"></script>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/template/template-svg.html b/third_party/webkit/PerformanceTests/MotionMark/tests/template/template-svg.html
new file mode 100644
index 0000000000..7a14fc45d6
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/tests/template/template-svg.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="../resources/stage.css">
+</head>
+<body>
+ <svg id="stage"></svg>
+ <script src="../../resources/strings.js"></script>
+ <script src="../../resources/extensions.js"></script>
+ <script src="../../resources/statistics.js"></script>
+ <script src="../resources/math.js"></script>
+ <script src="../resources/main.js"></script>
+ <script src="resources/template-svg.js"></script>
+</body>
+</html>
diff --git a/third_party/webkit/PerformanceTests/MotionMark/version b/third_party/webkit/PerformanceTests/MotionMark/version
new file mode 100644
index 0000000000..241f47c42d
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/MotionMark/version
@@ -0,0 +1,2 @@
+1.0
+r205655+ \ No newline at end of file