diff options
author | Aldo Cortesi <aldo@nullcube.com> | 2014-09-10 14:22:26 +1200 |
---|---|---|
committer | Aldo Cortesi <aldo@nullcube.com> | 2014-09-10 14:23:10 +1200 |
commit | 0510c9b111aed03d0d3680db63614d50f231745c (patch) | |
tree | 0d2fec5d46a3cb984a8b12e36db2f44a1a8eaa5a /web/src/vendor/benchmark/example/jsperf | |
parent | 76982937a68a2adaf96ec2d258e369d7c871a609 (diff) | |
download | mitmproxy-0510c9b111aed03d0d3680db63614d50f231745c.tar.gz mitmproxy-0510c9b111aed03d0d3680db63614d50f231745c.tar.bz2 mitmproxy-0510c9b111aed03d0d3680db63614d50f231745c.zip |
Client-side framework for web application
Diffstat (limited to 'web/src/vendor/benchmark/example/jsperf')
-rw-r--r-- | web/src/vendor/benchmark/example/jsperf/index.html | 287 | ||||
-rw-r--r-- | web/src/vendor/benchmark/example/jsperf/main.css | 588 | ||||
-rw-r--r-- | web/src/vendor/benchmark/example/jsperf/ui.js | 745 |
3 files changed, 1620 insertions, 0 deletions
diff --git a/web/src/vendor/benchmark/example/jsperf/index.html b/web/src/vendor/benchmark/example/jsperf/index.html new file mode 100644 index 00000000..040ddb63 --- /dev/null +++ b/web/src/vendor/benchmark/example/jsperf/index.html @@ -0,0 +1,287 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <meta name="description" content="This is just a test document for Benchmark.js."> + <title>Benchmark.js test page | jsPerf</title> + <!-- http://jsperf.com/benchmark-js-test-page --> + <link rel="stylesheet" href="main.css"> + <script>document.documentElement.className = 'js'</script> + <!--[if lt IE 9]><script src="https://raw.github.com/bestiejs/html5.js/master/html5.js"></script><![endif]--> + </head> + <body> + <article> + <hgroup> + <h1>Benchmark.js test page</h1> + <h2>JavaScript performance comparison</h2> + </hgroup> + + <p class="meta"> + Test case created by <a href="http://mathiasbynens.be/">Mathias</a> + <time datetime="2010-08-02T18:45:23+02:00" pubdate>40 seconds ago</time> + and last updated <time datetime="2010-08-02T18:45:51+02:00">12 seconds ago</time> + </p> + + <section> + <h2>Info</h2> + <p> + This is just a test document for Benchmark.js. + </p> + </section> + + <section id="prep-code"> + <h2>Preparation code</h2> + <pre><code><span + class="sc2"><<span class="kw2">div</span>></span>Lorem ipsum<span + class="sc2"><<span class="sy0">/</span><span class="kw2">div</span>></span><br><span + class="sc2"><<span class="kw2">script</span>></span><br> <span + class="kw2">var</span> arr <span class="sy0">=</span> <span class="br0">[</span><span + class="nu0">1</span><span class="sy0">,</span> <span class="nu0">5</span><span + class="sy0">,</span> <span class="nu0">4</span><span class="sy0">,</span> <span + class="nu0">2</span><span class="sy0">,</span> <span class="nu0">3</span><span + class="br0">]</span><span class="sy0">;</span><br><br> <span + class="kw2">function</span> init<span class="br0">(</span><span + class="br0">)</span> <span class="br0">{</span><br> window.<span + class="me1">console</span> <span class="sy0">&&</span> console.<span + class="me1">log</span><span class="br0">(</span><span class="st0">'init called'</span><span + class="br0">)</span><span class="sy0">;</span><br> <span + class="br0">}</span><br><span class="sc2"><<span class="sy0">/</span><span + class="kw2">script</span>></span><br><span class="sc2"><<span + class="kw2">script</span>></span><br>Benchmark.<span class="me1">prototype</span>.<span + class="me1">setup</span> <span class="sy0">=</span> <span class="kw2">function</span><span + class="br0">(</span><span class="br0">)</span> <span class="br0">{</span><br> window.<span + class="me1">foo</span> <span class="sy0">=</span> <span class="nu0">42</span><span + class="sy0">;</span><br> <span class="kw2">var</span> x <span + class="sy0">=</span> arr<span class="sy0">;</span><br><span class="br0">}</span><span + class="sy0">;</span><br><br>Benchmark.<span class="me1">prototype</span>.<span + class="me1">teardown</span> <span class="sy0">=</span> <span class="kw2">function</span><span + class="br0">(</span><span class="br0">) </span><span class="br0">{</span><br> window.<span + class="me1">foo</span> <span class="sy0">=</span> <span class="nu0">24</span><span + class="sy0">;</span><br><span class="br0">}</span><span class="sy0">;</span><br><span + class="sc2"><<span class="sy0">/</span><span class="kw2">script</span>></span></code></pre> + </section> + + <section> + <h2>Preparation code output</h2> + <div class="user-output"> + <div>Lorem ipsum</div> + </div> + </section> + + <section id="runner"> + <h2>Test runner</h2> + <p id="firebug"> + <strong>Warning! For accurate results, please disable Firebug before running the tests. <a href="http://jsperf.com/faq#firebug-warning">(Why?)</a></strong> + </p> + <p id="java"> + <strong>Java applet disabled.</strong> + </p> + <p id="status"> + <noscript> + <strong>To run the tests, please <a href="http://enable-javascript.com/">enable JavaScript</a> and reload the page.</strong> + </noscript> + </p> + <div id="controls"> + <button id="run" type="button"></button> + </div> + <table id="test-table"> + <caption>Testing in <span id="user-agent"></span></caption> + <thead> + <tr> + <th colspan="2">Test</th> + <th title="Operations per second (higher is better)">Ops/sec</th> + </tr> + </thead> + <tbody> + <tr> + <th scope="row" id="title-1"> + <div>Normal</div> + </th> + <td class="code"> + <pre><code>x.<span class="me1">sort</span><span class="br0">(</span><span + class="kw2">function</span><span class="br0">(</span>a<span + class="sy0">,</span> b<span class="br0">)</span> <span + class="br0">{</span><br> <span class="kw1">return</span> a <span + class="sy0">-</span> b<span class="sy0">;</span><br><span + class="br0">}</span><span class="br0">)</span><span + class="sy0">;</span></code></pre> + </td> + <td id="results-1" class="results"></td> + </tr> + <tr> + <th scope="row" id="title-2"> + <div>Exit Early</div> + </th> + <td class="code"> + <pre><code>x.<span class="me1">sort</span><span class="br0">(</span><span + class="kw2">function</span><span class="br0">(</span>a<span + class="sy0">,</span> b<span class="br0">)</span> <span + class="br0">{</span><br> <span class="kw1">return</span> a <span + class="sy0">-</span> b<span class="sy0">;</span><br><span + class="br0">}</span><span class="br0">)</span><span + class="sy0">;</span><br><span class="kw1">return</span><span + class="sy0">;</span></code></pre> + </td> + <td id="results-2" class="results"></td> + </tr> + <tr> + <th scope="row" id="title-3"> + <div>Async</div> + </th> + <td class="code"> + <pre><code><strong class="co1">// async test</strong><br>setTimeout<span + class="br0">(</span><span class="kw2">function</span><span + class="br0">(</span><span class="br0">)</span> <span + class="br0">{</span><br> deferred.<span + class="me1">resolve</span><span class="br0">(</span><span + class="br0">)</span><span class="sy0">;</span><br><span + class="br0">}</span><span class="sy0">,</span> <span + class="nu0">10</span><span class="br0">)</span><span + class="sy0">;</span></code></pre> + </td> + <td id="results-3" class="results"></td> + </tr> + <tr> + <th scope="row" id="title-4"> + <div>Error</div> + </th> + <td class="code"> + <pre><code>x.<span class="me1">foo</span><span class="br0">(</span><span + class="br0">)</span><span class="sy0">;</span> <span + class="co1">// unknown method</span></code></pre> + </td> + <td id="results-4" class="results"></td> + </tr> + <tr> + <th scope="row" id="title-5"> + <div>Comments</div> + </th> + <td class="code"> + <pre><code><span class="co1">// comments at start</span><br>x.<span + class="me1">reverse</span><span class="br0">(</span><span + class="br0">)</span>.<span class="me1">sort</span><span + class="br0">(</span><span class="kw2">function</span><span + class="br0">(</span>a<span class="sy0">,</span> b<span + class="br0">)</span> <span class="br0">{</span><br> <span + class="kw1">return</span> a <span class="sy0">-</span> b<span + class="sy0">;</span><br><span class="br0">}</span><span + class="br0">)</span><span class="sy0">;</span><br><span + class="co1">// comments at end</span></code></pre> + </td> + <td id="results-5" class="results"></td> + </tr> + </tbody> + </table> + + <p> + You can <a href="#" rel="nofollow">edit these tests or add even more tests to this page</a> + by appending <code>/edit</code> to the URL. + </p> + </section> + + <section> + <h2 id="results">Compare results of other browsers</h2> + <div id="bs-results"></div> + </section> + + <section id="comments"> + <h1>0 comments</h1> + <div id="comments-wrapper"> + <form action="#comment-form" method="post" id="comment-form"> + <fieldset> + <h2>Add a comment</h2> + <div> + <label for="author">Name <em title="This field is required">*</em></label> + <input type="text" name="author" id="author" required> + </div> + <div> + <label for="author-email">Email <em title="This field is required">*</em></label> + <label class="inline"> + <input type="email" name="author-email" id="author-email" required> (only used for Gravatar) + </label> + </div> + <div> + <label for="author-url">URL </label> + <input type="url" name="author-url" id="author-url"> + </div> + <div> + <label for="message">Message <em title="This field is required">*</em><span>Markdown syntax is allowed</span></label> + <textarea name="message" id="message" required></textarea> + </div> + <div class="question"> + <label for="question">Are you a spammer? <span>(just answer the question)</span></label> + <input type="text" name="question" id="question"> + </div> + <div class="buttons"> + <input type="submit" class="submit" value="Add comment"> + </div> + </fieldset> + </form> + </div> + </section> + </article> + + <footer> + © 2011 <a href="http://jsperf.com/">jsPerf.com</a> + · <a href="http://jsperf.com/browse">Browse</a> + · <a href="http://jsperf.com/popular">Popular tests</a> + · <a href="http://jsperf.com/faq">FAQ</a> + · <a href="http://jsperf.com/faq#donate">Donate</a> + · <a href="http://twitter.com/jsprf" rel="nofollow">twitter: @jsprf</a> + · <a href="http://benchmarkjs.com/">Benchmark.js</a> + · by <a href="http://mathiasbynens.be/" title="Mathias Bynens, front-end web developer">@mathias</a> + </footer> + + <script src="../../vendor/platform.js/platform.js"></script> + <script src="../../benchmark.js"></script> + <script src="ui.js"></script> + <script src="../../plugin/ui.browserscope.js"></script> + <script> + var arr = [1, 5, 4, 2, 3]; + + function init() { + window.console && console.log('init called'); + } + </script> + <script> + ui.browserscope.key = 'agt1YS1wcm9maWxlcnINCxIEVGVzdBjR6NELDA'; + ui.browserscope.selector = '#bs-results'; + + ui.add('Normal', '\ + x.sort(function(a, b) {\n\ + return a - b;\n\ + });' + ) + .add('Exit Early', '\ + x.sort(function(a, b) {\n\ + return a - b;\n\ + });\n\ + return;' + ) + .add('Async', { + 'defer': true, + 'fn': '\ + setTimeout(function() {\n\ + deferred.resolve();\n\ + }, 10);' + }) + .add('Error', '\ + x.foo(); // unknown method' + ) + .add('Comments', '\ + // comments at start\n\ + x.reverse().sort(function(a, b) {\n\ + return a - b;\n\ + });\n\ + // comments at end' + ); + + Benchmark.prototype.setup = '\ + window.foo = 42;\n\ + var x = arr;'; + + Benchmark.prototype.teardown = '\ + window.foo = 24;'; + </script> + </body> +</html> diff --git a/web/src/vendor/benchmark/example/jsperf/main.css b/web/src/vendor/benchmark/example/jsperf/main.css new file mode 100644 index 00000000..52d42ef9 --- /dev/null +++ b/web/src/vendor/benchmark/example/jsperf/main.css @@ -0,0 +1,588 @@ +html, body, h1, h2, h3, fieldset, #faq, #faq dt, #faq dd { + margin: 0; + padding: 0; + border: 0; +} + +table, p, ul, h1, h2, h3, #error-info, form div, #faq, .bs-rt { + margin-bottom: 1em; +} + +button, input, textarea, a, .bs-rt { + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; +} + +html, input, textarea, button { + font: 1em/1.5 sans-serif; +} + +html { + background: #c4c4c4; + height: 100%; +} + +body { + background: #fff; + border: solid #aaa; + border-width: 0 1px; + width: 60em; + padding: 0 2.5em; + margin: 0 auto; + min-height: 100%; +} + +a { + color: #357ab0; + padding: .2em; +} + +a:hover, a:focus { + text-decoration: none; +} + +blockquote { + margin: 0 0 1em; + border-left: 5px solid #b4b4b4; + padding-left: .5em; +} + +table { + width: 100%; + border-collapse: collapse; +} + +thead th, button:hover, button:focus, .submit:hover, .submit:focus, a:hover, a:focus, #comments .meta a:hover, #comments .meta a:focus, li.current a:hover, li.current a:focus, form h3, #comments .owner .meta { + background: #1a6ab9; + background-image: -moz-linear-gradient(top, #6ca5dd, #1a6ab9); + background-image: -o-linear-gradient(top, #6ca5dd, #1a6ab9); + background-image: -webkit-gradient(linear, left top, left bottom, from(#6ca5dd), to(#1a6ab9)); + background-image: -webkit-linear-gradient(#6ca5dd, #1a6ab9); + background-image: linear-gradient(top, #6ca5dd, #1a6ab9); + filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#6ca5dd', EndColorStr='#1a6ab9'); + color: #fff; +} + +caption, #comments .meta { + background: #bcbcbc; + background-image: -moz-linear-gradient(top, #d0d0d0, #a7a7a7); + background-image: -o-linear-gradient(top, #d0d0d0, #a7a7a7); + background-image: -webkit-gradient(linear, left top, left bottom, from(#d0d0d0), to(#a7a7a7)); + background-image: -webkit-linear-gradient(#d0d0d0, #a7a7a7); + background-image: linear-gradient(top, #d0d0d0, #a7a7a7); + filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#d0d0d0', EndColorStr='#a7a7a7'); + color: #555; +} + +thead th, caption { + font-weight: bold; +} + +.js tbody th:hover, .js tbody th:focus { + text-decoration: underline; + cursor: pointer; +} + +tbody th, td { + border: solid #b4b4b4; + border-width: 0 1px 1px 0; +} + +tbody th { + background: #dde4ea; + min-width: 100px; +} + +tbody th div { + max-width: 200px; + word-wrap: break-word; + overflow: auto; +} + +td.results { + text-align: center; + border-right: 0; +} + +.results span, small { + display: block; + font-size: .8em; +} + +td, th, caption { + padding: .2em .5em; +} + +td.fastest { + background: #9cee82; +} + +tr:last-child td, tr:last-child th { + border-bottom: 0; +} + +td.slowest, td.error, .invalid { + background: pink; +} + +/* needs its own rule because of buggy IE */ +:focus:invalid { + background: pink; +} + +td.error { + text-transform: uppercase; + font-weight: bold; +} + +button, .submit { + padding: .35em .5em; + cursor: pointer; + color: #000; + border: 1px solid #999; + background: #dadada; + background-image: -moz-linear-gradient(top, #ebebeb, #b8b8b8); + background-image: -o-linear-gradient(top, #ebebeb, #b8b8b8); + background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#b8b8b8)); + background-image: -webkit-linear-gradient(top, #ebebeb, #b8b8b8); + background-image: linear-gradient(top, #ebebeb, #b8b8b8); + filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#ebebeb', EndColorStr='#b8b8b8'); +} + +a:hover span, a:focus span, #comments .owner .meta a { + color: #fff; +} + +#controls, #run, .buttons { + float: right; +} + +button:hover, button:focus, .submit:hover, .submit:focus { + border-color: #357ab0 +} + +#add-buttons button { + padding: .15em .4em; + font-size: 11px; + font-weight: bold; +} + +form label { + float: left; + width: 14em; + cursor: pointer; + text-align: right; + margin-right: 1em; + padding: .4em; +} + +label.inline { + float: none; + padding: 0; + margin: 0; +} + +label[for="visible"], label[for$="][defer]"] { + position: relative; + top: -.37em; +} + +label span { + display: block; + font-size: 90%; + color: #b4b4b4; +} + +label em { + color: red; + font-style: normal; +} + +.js #advanced { + display: none; +} + +#show-advanced { + display: none; +} + +.js #show-advanced { + display: block; +} + +section { + display: block; + border-top: 1px solid #ccc; + padding-top: 2em; + margin: 2em 0; +} + +textarea { + resize: vertical; + height: 15em; + width: 42.6em; + *width: 42.4em; /* IE < 8 */ +} + +input, textarea { + border: 1px solid #b4b4b4; + padding: .4em; +} + +#visible, #calibrate { /* checkboxes, for IE */ + border: 0; + padding: 0; +} + +form h2, form h3, form h4, p.error, .preview, #add-libraries, #add-buttons { + padding-left: 250px; + display: block; +} + +.js .question, hgroup h2, #controls, #firebug, #java { + display: none; +} + +pre { + width: 100%; + overflow: auto; +} + +table #results-1 { + width: 100px; +} + +table pre { + *padding: 1.5em 0; /* IE < 8 */ + *overflow-y: hidden; /* IE < 8 */ +} + +table pre, table td.code { + width: 650px; +} + +mark { + background: #ff9; + padding: .2em .1em; +} + +h1, h2, h3, h4 { + font-weight: bold; + font-size: 1em; +} + +h1 { + padding-top: 1em; + font-size: 1.4em; +} + +form h3 { + padding-top: .2em; + padding-bottom: .2em; +} + +h1 em { + font-style: normal; +} + +h1 strong { + font-style: italic; + font-family: Monaco, 'Lucida Console', monospace; +} + +li.current a { + background: #90ee85; +} + +#donate { + display: block; + background: #ffffdc; + border: 1px solid #faa700; + padding: 1em; +} + +#donate h1 { + padding-top: 0; + font-size: 16px; +} + +#paypal { + text-align: center; +} + +footer { + display: block; + margin-top: 2em; + padding: .5em 0 1.5em; + border-top: 2px solid #c4c4c4; +} + +#add-test { + margin-right: .3em; +} + +#bs-chart { + overflow: auto; +} + +#bs-logo { + margin: 0; +} + +#bs-logo span, applet { + position: absolute; + left: -9999em; +} + +#bs-logo a { + display: block; + width: 232px; + height: 39px; + filter: none; + background: url(//www.browserscope.org/static/img/logo.png) 0 0 no-repeat; +} + +#bs-ua { + padding: .5em .5em 0; + color: #555; +} + +#bs-results .bs-rt { + font-size: 10pt; + padding: .5em; + background: #ddd; +} + +#bs-results td { + border: 1px solid #ddd; + padding: .4em; + white-space: nowrap; +} + +#bs-results .rt-ua-cur { + font-style: italic; + font-weight: bold; +} + +#bs-results .bs-rt-message { + padding: 3em; + text-align: center; + font-weight: bold; + color: #555; +} + +#bs-results .google-visualization-table-tr-head td { + white-space: normal; +} + +#controls { + margin-top: -3.35em; +} + +#comments h1 { + padding: 0; +} + +#comments .meta img { + position: absolute; + left: 0; + top: 0; + margin: 0; +} + +#comments .meta img { + top: 2px; + left: 2px; +} + +#comments .meta { + padding-left: 35px; + margin-top: 0; + width: 923px; + line-height: 30px; +} + +#comments .meta a { + font-weight: bold; + color: #555; +} + +#comments article div { + padding: 0 1em 0; +} + +#comments article { + display: block; + border: 1px solid #b4b4b4; + position: relative; + margin-bottom: 1em; +} + +/* needs its own rule (cannot be grouped with `tbody th`) because of buggy IE */ +#comments article:target { + background: #dde4ea; +} + +#error-info.show, .meta strong, #firebug strong, #java strong, #status strong { + background: pink; + border: 1px solid #b00b00; + padding: .4em; +} + +#error-info.show { + padding: .5em 1em; +} + +#error-info, code, samp, var, textarea, #slug { + font-family: Monaco, monospace; + font-size: .9em; +} + +#java strong { + background: #ffffdc; + border: 1px solid #faa700; +} + +#slug { + font-size: 1em; +} + +#faq dt { + margin-top: 1em; + font-weight: bold; +} + +#faq dt a { + display: none; +} + +#faq dt:hover a { + display: inline; +} + +#faq dt:target, #faq dt:target + dd { + background: #90ee85; + margin: 0 -.8em; + padding: 0 .8em; +} + +#faq dt:target + dd { + padding-bottom: .5em; + margin-bottom: -.5em; +} + +#faq dt:target { + margin-top: .5em; + padding-top: .5em; +} + +#firebug, #java, #status { + margin: 0 0 1em; + padding: .3em 0; +} + +#prep-code pre { + max-height: 500px; + overflow: auto; +} + +#controls.show, #firebug.show, #java.show { + display: block; +} + +.co1, .co2, .coMULTI { + font-style: italic; +} + +.error { + color: #b00b00; +} + +.imp { + color: red; +} + +.kw1, .kw3 { + color: #006; +} + +.kw2 { + color: #036; +} + +.co1, .coMULTI { + color: #060; +} + +.co2 { + color: #096; +} + +.es0 { + color: #009; +} + +.br0 { + color: #090; +} + +.sy0 { + color: #393; +} + +.st0 { + color: #36c; +} + +.nu0 { + color: #c00; +} + +.me1 { + color: #606; +} + +/* < 1051px */ +@media (max-width: 1050px) { + table pre, table td.code { + width: 550px; + } +} + +/* < 1041px */ +@media (max-width: 1040px) { + body { + margin: 0; + border: 0; + } + + body, #comments .meta { + width: 100%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + +} + +/* < 801px */ +@media (max-width: 800px) { + table pre, table td.code { + width: 450px; + } +} + +/* < 681px */ +@media (max-width: 680px) { + table pre, table td.code { + width: 350px; + } +} + +/* < 651px */ +@media (max-width: 650px) { + table pre, table td.code { + width: 200px; + } +} diff --git a/web/src/vendor/benchmark/example/jsperf/ui.js b/web/src/vendor/benchmark/example/jsperf/ui.js new file mode 100644 index 00000000..8270cd66 --- /dev/null +++ b/web/src/vendor/benchmark/example/jsperf/ui.js @@ -0,0 +1,745 @@ +/*! + * ui.js + * Copyright Mathias Bynens <http://mths.be/> + * Modified by John-David Dalton <http://allyoucanleet.com/> + * Available under MIT license <http://mths.be/mit> + */ +(function(window, document) { + + /** Java applet archive path */ + var archive = '../../nano.jar'; + + /** Cache of error messages */ + var errors = []; + + /** Google Analytics account id */ + var gaId = ''; + + /** Cache of event handlers */ + var handlers = {}; + + /** A flag to indicate that the page has loaded */ + var pageLoaded = false; + + /** Benchmark results element id prefix (e.g. `results-1`) */ + var prefix = 'results-'; + + /** The element responsible for scrolling the page (assumes ui.js is just before </body>) */ + var scrollEl = document.body; + + /** Used to resolve a value's internal [[Class]] */ + var toString = {}.toString; + + /** Namespace */ + var ui = new Benchmark.Suite; + + /** Object containing various CSS class names */ + var classNames = { + // used for error styles + 'error': 'error', + // used to make content visible + 'show': 'show', + // used to reset result styles + 'results': 'results' + }; + + /** Used to flag environments/features */ + var has = { + // used for pre-populating form fields + 'localStorage': !!function() { + try { + return !localStorage.getItem(+new Date); + } catch(e) { } + }(), + // used to distinguish between a regular test page and an embedded chart + 'runner': !!$('runner') + }; + + /** Object containing various text messages */ + var texts = { + // inner text for the various run button states + 'run': { + 'again': 'Run again', + 'ready': 'Run tests', + 'running': 'Stop running' + }, + // common status values + 'status': { + 'again': 'Done. Ready to run again.', + 'ready': 'Ready to run.' + } + }; + + /** The options object for Benchmark.Suite#run */ + var runOptions = { + 'async': true, + 'queued': true + }; + + /** API shortcuts */ + var each = Benchmark.each, + extend = Benchmark.extend, + filter = Benchmark.filter, + forOwn = Benchmark.forOwn, + formatNumber = Benchmark.formatNumber, + indexOf = Benchmark.indexOf, + invoke = Benchmark.invoke, + join = Benchmark.join; + + /*--------------------------------------------------------------------------*/ + + handlers.benchmark = { + + /** + * The onCycle callback, used for onStart as well, assigned to new benchmarks. + * + * @private + */ + 'cycle': function() { + var bench = this, + size = bench.stats.sample.length; + + if (!bench.aborted) { + setStatus(bench.name + ' × ' + formatNumber(bench.count) + ' (' + + size + ' sample' + (size == 1 ? '' : 's') + ')'); + } + }, + + /** + * The onStart callback assigned to new benchmarks. + * + * @private + */ + 'start': function() { + // call user provided init() function + if (isFunction(window.init)) { + init(); + } + } + }; + + handlers.button = { + + /** + * The "run" button click event handler used to run or abort the benchmarks. + * + * @private + */ + 'run': function() { + var stopped = !ui.running; + ui.abort(); + ui.length = 0; + + if (stopped) { + logError({ 'clear': true }); + ui.push.apply(ui, filter(ui.benchmarks, function(bench) { + return !bench.error && bench.reset(); + })); + ui.run(runOptions); + } + } + }; + + handlers.title = { + + /** + * The title table cell click event handler used to run the corresponding benchmark. + * + * @private + * @param {Object} event The event object. + */ + 'click': function(event) { + event || (event = window.event); + + var id, + index, + target = event.target || event.srcElement; + + while (target && !(id = target.id)) { + target = target.parentNode; + } + index = id && --id.split('-')[1] || 0; + ui.push(ui.benchmarks[index].reset()); + ui.running ? ui.render(index) : ui.run(runOptions); + }, + + /** + * The title cell keyup event handler used to simulate a mouse click when hitting the ENTER key. + * + * @private + * @param {Object} event The event object. + */ + 'keyup': function(event) { + if (13 == (event || window.event).keyCode) { + handlers.title.click(event); + } + } + }; + + handlers.window = { + + /** + * The window hashchange event handler supported by Chrome 5+, Firefox 3.6+, and IE8+. + * + * @private + */ + 'hashchange': function() { + ui.parseHash(); + + var scrollTop, + params = ui.params, + chart = params.chart, + filterBy = params.filterby; + + if (pageLoaded) { + // configure posting + ui.browserscope.postable = has.runner && !('nopost' in params); + + // configure chart renderer + if (chart || filterBy) { + scrollTop = $('results').offsetTop; + ui.browserscope.render({ 'chart': chart, 'filterBy': filterBy }); + } + if (has.runner) { + // call user provided init() function + if (isFunction(window.init)) { + init(); + } + // auto-run + if ('run' in params) { + scrollTop = $('runner').offsetTop; + setTimeout(handlers.button.run, 1); + } + // scroll to the relevant section + if (scrollTop) { + scrollEl.scrollTop = scrollTop; + } + } + } + }, + + /** + * The window load event handler used to initialize the UI. + * + * @private + */ + 'load': function() { + // only for pages with a comment form + if (has.runner) { + // init the ui + addClass('controls', classNames.show); + addListener('run', 'click', handlers.button.run); + + setHTML('run', texts.run.ready); + setHTML('user-agent', Benchmark.platform); + setStatus(texts.status.ready); + + // answer spammer question + $('question').value = 'no'; + + // prefill author details + if (has.localStorage) { + each([$('author'), $('author-email'), $('author-url')], function(element) { + element.value = localStorage[element.id] || ''; + element.oninput = element.onkeydown = function(event) { + event && event.type < 'k' && (element.onkeydown = null); + localStorage[element.id] = element.value; + }; + }); + } + // show warning when Firebug is enabled (avoids showing for Firebug Lite) + try { + // Firebug 1.9 no longer has `console.firebug` + if (console.firebug || /firebug/i.test(console.table())) { + addClass('firebug', classNames.show); + } + } catch(e) { } + } + // evaluate hash values + // (delay in an attempt to ensure this is executed after all other window load handlers) + setTimeout(function() { + pageLoaded = true; + handlers.window.hashchange(); + }, 1); + } + }; + + /*--------------------------------------------------------------------------*/ + + /** + * Shortcut for document.getElementById(). + * + * @private + * @param {Element|String} id The id of the element to retrieve. + * @returns {Element} The element, if found, or null. + */ + function $(id) { + return typeof id == 'string' ? document.getElementById(id) : id; + } + + /** + * Adds a CSS class name to an element's className property. + * + * @private + * @param {Element|String} element The element or id of the element. + * @param {String} className The class name. + * @returns {Element} The element. + */ + function addClass(element, className) { + if ((element = $(element)) && !hasClass(element, className)) { + element.className += (element.className ? ' ' : '') + className; + } + return element; + } + + /** + * Registers an event listener on an element. + * + * @private + * @param {Element|String} element The element or id of the element. + * @param {String} eventName The name of the event. + * @param {Function} handler The event handler. + * @returns {Element} The element. + */ + function addListener(element, eventName, handler) { + if ((element = $(element))) { + if (typeof element.addEventListener != 'undefined') { + element.addEventListener(eventName, handler, false); + } else if (typeof element.attachEvent != 'undefined') { + element.attachEvent('on' + eventName, handler); + } + } + return element; + } + + /** + * Appends to an element's innerHTML property. + * + * @private + * @param {Element|String} element The element or id of the element. + * @param {String} html The HTML to append. + * @returns {Element} The element. + */ + function appendHTML(element, html) { + if ((element = $(element)) && html != null) { + element.innerHTML += html; + } + return element; + } + + /** + * Shortcut for document.createElement(). + * + * @private + * @param {String} tag The tag name of the element to create. + * @returns {Element} A new element of the given tag name. + */ + function createElement(tagName) { + return document.createElement(tagName); + } + + /** + * Checks if an element is assigned the given class name. + * + * @private + * @param {Element|String} element The element or id of the element. + * @param {String} className The class name. + * @returns {Boolean} If assigned the class name return true, else false. + */ + function hasClass(element, className) { + return !!(element = $(element)) && + (' ' + element.className + ' ').indexOf(' ' + className + ' ') > -1; + } + + /** + * Set an element's innerHTML property. + * + * @private + * @param {Element|String} element The element or id of the element. + * @param {String} html The HTML to set. + * @returns {Element} The element. + */ + function setHTML(element, html) { + if ((element = $(element))) { + element.innerHTML = html == null ? '' : html; + } + return element; + } + + /*--------------------------------------------------------------------------*/ + + /** + * Gets the Hz, i.e. operations per second, of `bench` adjusted for the + * margin of error. + * + * @private + * @param {Object} bench The benchmark object. + * @returns {Number} Returns the adjusted Hz. + */ + function getHz(bench) { + return 1 / (bench.stats.mean + bench.stats.moe); + } + + /** + * Checks if a value has an internal [[Class]] of Function. + * + * @private + * @param {Mixed} value The value to check. + * @returns {Boolean} Returns `true` if the value is a function, else `false`. + */ + function isFunction(value) { + return toString.call(value) == '[object Function]'; + } + + /** + * Appends to or clears the error log. + * + * @private + * @param {String|Object} text The text to append or options object. + */ + function logError(text) { + var table, + div = $('error-info'), + options = {}; + + // juggle arguments + if (typeof text == 'object' && text) { + options = text; + text = options.text; + } + else if (arguments.length) { + options.text = text; + } + if (!div) { + table = $('test-table'); + div = createElement('div'); + div.id = 'error-info'; + table.parentNode.insertBefore(div, table.nextSibling); + } + if (options.clear) { + div.className = div.innerHTML = ''; + errors.length = 0; + } + if ('text' in options && indexOf(errors, text) < 0) { + errors.push(text); + addClass(div, classNames.show); + appendHTML(div, text); + } + } + + /** + * Sets the status text. + * + * @private + * @param {String} text The text to write to the status. + */ + function setStatus(text) { + setHTML('status', text); + } + + /*--------------------------------------------------------------------------*/ + + /** + * Parses the window.location.hash value into an object assigned to `ui.params`. + * + * @static + * @memberOf ui + * @returns {Object} The suite instance. + */ + function parseHash() { + var me = this, + hashes = location.hash.slice(1).split('&'), + params = me.params || (me.params = {}); + + // remove old params + forOwn(params, function(value, key) { + delete params[key]; + }); + + // add new params + each(hashes[0] && hashes, function(value) { + value = value.split('='); + params[value[0].toLowerCase()] = (value[1] || '').toLowerCase(); + }); + return me; + } + + /** + * Renders the results table cell of the corresponding benchmark(s). + * + * @static + * @memberOf ui + * @param {Number} [index] The index of the benchmark to render. + * @returns {Object} The suite instance. + */ + function render(index) { + each(index == null ? (index = 0, ui.benchmarks) : [ui.benchmarks[index]], function(bench) { + var parsed, + cell = $(prefix + (++index)), + error = bench.error, + hz = bench.hz; + + // reset title and class + cell.title = ''; + cell.className = classNames.results; + + // status: error + if (error) { + setHTML(cell, 'Error'); + addClass(cell, classNames.error); + parsed = join(error, '</li><li>'); + logError('<p>' + error + '.</p>' + (parsed ? '<ul><li>' + parsed + '</li></ul>' : '')); + } + else { + // status: running + if (bench.running) { + setHTML(cell, 'running…'); + } + // status: completed + else if (bench.cycles) { + // obscure details until the suite has completed + if (ui.running) { + setHTML(cell, 'completed'); + } + else { + cell.title = 'Ran ' + formatNumber(bench.count) + ' times in ' + + bench.times.cycle.toFixed(3) + ' seconds.'; + setHTML(cell, formatNumber(hz.toFixed(hz < 100 ? 2 : 0)) + + ' <small>±' + bench.stats.rme.toFixed(2) + '%</small>'); + } + } + else { + // status: pending + if (ui.running && ui.indexOf(bench) > -1) { + setHTML(cell, 'pending…'); + } + // status: ready + else { + setHTML(cell, 'ready'); + } + } + } + }); + return ui; + } + + /*--------------------------------------------------------------------------*/ + + ui.on('add', function(event) { + var bench = event.target, + index = ui.benchmarks.length, + id = index + 1, + title = $('title-' + id); + + delete ui[--ui.length]; + ui.benchmarks.push(bench); + + if (has.runner) { + title.tabIndex = 0; + title.title = 'Click to run this test again.'; + + addListener(title, 'click', handlers.title.click); + addListener(title, 'keyup', handlers.title.keyup); + + bench.on('start', handlers.benchmark.start); + bench.on('start cycle', handlers.benchmark.cycle); + ui.render(index); + } + }) + .on('start cycle', function() { + ui.render(); + setHTML('run', texts.run.running); + }) + .on('complete', function() { + var benches = filter(ui.benchmarks, 'successful'), + fastest = filter(benches, 'fastest'), + slowest = filter(benches, 'slowest'); + + ui.render(); + setHTML('run', texts.run.again); + setStatus(texts.status.again); + + // highlight result cells + each(benches, function(bench) { + var cell = $(prefix + (indexOf(ui.benchmarks, bench) + 1)), + fastestHz = getHz(fastest[0]), + hz = getHz(bench), + percent = (1 - (hz / fastestHz)) * 100, + span = cell.getElementsByTagName('span')[0], + text = 'fastest'; + + if (indexOf(fastest, bench) > -1) { + // mark fastest + addClass(cell, text); + } + else { + text = isFinite(hz) + ? formatNumber(percent < 1 ? percent.toFixed(2) : Math.round(percent)) + '% slower' + : ''; + + // mark slowest + if (indexOf(slowest, bench) > -1) { + addClass(cell, 'slowest'); + } + } + // write ranking + if (span) { + setHTML(span, text); + } else { + appendHTML(cell, '<span>' + text + '</span>'); + } + }); + + ui.browserscope.post(); + }); + + /*--------------------------------------------------------------------------*/ + + /** + * An array of benchmarks created from test cases. + * + * @memberOf ui + * @type Array + */ + ui.benchmarks = []; + + /** + * The parsed query parameters of the pages url hash. + * + * @memberOf ui + * @type Object + */ + ui.params = {}; + + // parse query params into ui.params hash + ui.parseHash = parseHash; + + // (re)render the results of one or more benchmarks + ui.render = render; + + /*--------------------------------------------------------------------------*/ + + // expose + window.ui = ui; + + // don't let users alert, confirm, prompt, or open new windows + window.alert = window.confirm = window.prompt = window.open = function() { }; + + // parse hash query params when it changes + addListener(window, 'hashchange', handlers.window.hashchange); + + // bootstrap onload + addListener(window, 'load', handlers.window.load); + + // parse location hash string + ui.parseHash(); + + // provide a simple UI for toggling between chart types and filtering results + // (assumes ui.js is just before </body>) + (function() { + var sibling = $('bs-results'), + p = createElement('p'); + + p.innerHTML = + '<span id=charts><strong>Chart type:</strong> <a href=#>bar</a>, ' + + '<a href=#>column</a>, <a href=#>line</a>, <a href=#>pie</a>, ' + + '<a href=#>table</a></span><br>' + + '<span id=filters><strong>Filter:</strong> <a href=#>popular</a>, ' + + '<a href=#>all</a>, <a href=#>desktop</a>, <a href=#>family</a>, ' + + '<a href=#>major</a>, <a href=#>minor</a>, <a href=#>mobile</a>, ' + + '<a href=#>prerelease</a></span>'; + + sibling.parentNode.insertBefore(p, sibling); + + // use DOM0 event handler to simplify canceling the default action + $('charts').onclick = + $('filters').onclick = function(event) { + event || (event = window.event); + var target = event.target || event.srcElement; + if (target.href || (target = target.parentNode).href) { + ui.browserscope.render( + target.parentNode.id == 'charts' + ? { 'chart': target.innerHTML } + : { 'filterBy': target.innerHTML } + ); + } + // cancel the default action + return false; + }; + }()); + + /*--------------------------------------------------------------------------*/ + + // fork for runner or embedded chart + if (has.runner) { + // detect the scroll element + (function() { + var scrollTop, + div = document.createElement('div'), + body = document.body, + bodyStyle = body.style, + bodyHeight = bodyStyle.height, + html = document.documentElement, + htmlStyle = html.style, + htmlHeight = htmlStyle.height; + + bodyStyle.height = htmlStyle.height = 'auto'; + div.style.cssText = 'display:block;height:9001px;'; + body.insertBefore(div, body.firstChild); + scrollTop = html.scrollTop; + + // set `scrollEl` that's used in `handlers.window.hashchange()` + if (html.clientWidth !== 0 && ++html.scrollTop && html.scrollTop == scrollTop + 1) { + scrollEl = html; + } + body.removeChild(div); + bodyStyle.height = bodyHeight; + htmlStyle.height = htmlHeight; + html.scrollTop = scrollTop; + }()); + + // catch and display errors from the "preparation code" + window.onerror = function(message, fileName, lineNumber) { + logError('<p>' + message + '.</p><ul><li>' + join({ + 'message': message, + 'fileName': fileName, + 'lineNumber': lineNumber + }, '</li><li>') + '</li></ul>'); + scrollEl.scrollTop = $('error-info').offsetTop; + }; + // inject nano applet + // (assumes ui.js is just before </body>) + if ('nojava' in ui.params) { + addClass('java', classNames.show); + } else { + // using innerHTML avoids an alert in some versions of IE6 + document.body.insertBefore(setHTML(createElement('div'), + '<applet code=nano archive=' + archive + '>').lastChild, document.body.firstChild); + } + } + else { + // short circuit unusable methods + ui.render = function() { }; + ui.off('start cycle complete'); + setTimeout(function() { + ui.off(); + ui.browserscope.post = function() { }; + invoke(ui.benchmarks, 'off'); + }, 1); + } + + /*--------------------------------------------------------------------------*/ + + // optimized asynchronous Google Analytics snippet based on + // http://mathiasbynens.be/notes/async-analytics-snippet + if (gaId) { + (function() { + var script = createElement('script'), + sibling = document.getElementsByTagName('script')[0]; + + window._gaq = [['_setAccount', gaId], ['_trackPageview']]; + script.src = '//www.google-analytics.com/ga.js'; + sibling.parentNode.insertBefore(script, sibling); + }()); + } +}(this, document)); |