Home | History | Annotate | Download | only in web
      1 (function(){
      2         
      3         // Populated from: http://www.medcalc.be/manual/t-distribution.php
      4         // 95% confidence for N - 1 = 4
      5         var tDistribution = 2.776;
      6         
      7         // The number of individual test iterations to do
      8         var numTests = 5;
      9         
     10         // The type of run that we're doing (options are "runs/s" or "ms")
     11         var runStyle = "runs/s";
     12         
     13         // A rough estimate, in seconds, of how long it'll take each test
     14         // iteration to run
     15         var timePerTest = runStyle === "runs/s" ? 1 : 0.5;
     16         
     17         // Initialize a batch of tests
     18         //  name = The name of the test collection
     19         this.startTest = function(name, version){
     20                 numloaded++;
     21                 if ( numloaded == totalTests )
     22                         setTimeout( init, 100 );
     23 
     24                 testName = name;
     25                 if ( !queues[testName] ) return;
     26                 testID = testName;
     27                 testNames[testID] = testName;
     28                 testVersions[testID] = version || 0;
     29                 testSummary[testID] = testSummaryNum[testID] = testDone[testID] = testNum[testID] = 0;
     30 
     31                 queues[testID].push(function(){
     32                         summary = 0;
     33                         dequeue();
     34                 });
     35         };
     36 
     37         // Anything that you want to have run in order, but not actually test
     38         this.prep = function(fn){
     39                 if ( !queues[testName] ) return;
     40                 queues[testID].push(function(){
     41                         fn();
     42                         dequeue();
     43                 });
     44         };
     45 
     46         // End the tests and finalize the report
     47         this.endTest = function(){
     48                 if ( !queues[testName] ) return;
     49                 // Save the summary output until all the test are complete
     50                 queues[testID].push(function(){
     51                         dequeue();
     52                 });
     53         };
     54 
     55         // Run a new test
     56         //  name = The unique name of the test
     57         //  num = The 'length' of the test (length of string, # of tests, etc.)
     58         //  fn = A function holding the test to run
     59         this.test = function(name, num, fn){
     60                 if ( !queues[testName] ) return;
     61                 // Save the summary output until all the test are complete
     62                 var curTest = testName, curID = testID;
     63 
     64                 if ( arguments.length === 3 ) {
     65                         if ( !nameDone[name] )
     66                                 nameDone[name] = 0;
     67                         nameDone[name]++;
     68         
     69                         if ( nameDone[name] != 3 )
     70                                 return; 
     71                 } else {
     72                         fn = num;
     73                         num = 1;
     74                 }
     75 
     76                 time += timePerTest * numTests;
     77 
     78                 testNum[curID]++;
     79 
     80                 // Don't execute the test immediately
     81                 queues[testID].push(function(){
     82                         title = name;
     83                         var times = [], start, pos = 0, cur;
     84                         
     85                         setTimeout(function(){
     86                                 // run tests
     87                                 try {
     88                                         if ( doShark(name) ) {
     89                                                 connectShark();
     90                                                 startShark();
     91                                         }
     92                                         
     93                                         start = (new Date()).getTime();
     94                                         
     95                                         if ( runStyle === "runs/s" ) {
     96                                                 var runs = 0;
     97                                                 
     98                                                 cur = (new Date()).getTime();
     99                                                 
    100                                                 while ( (cur - start) < 1000 ) {
    101                                                         fn();
    102                                                         cur = (new Date()).getTime();
    103                                                         runs++;
    104                                                 }
    105                                         } else {
    106                                                 fn();
    107                                                 cur = (new Date()).getTime();
    108                                         }
    109 
    110                                         if ( doShark(name) ) {
    111                                                 stopShark();
    112                                                 disconnectShark();
    113                                         }
    114                                         
    115                                         // For making Median and Variance
    116                                         if ( runStyle === "runs/s" ) {
    117                                                 times.push( (runs * 1000) / (cur - start) );
    118                                         } else {
    119                                                 times.push( cur - start );
    120                                         }
    121                                 } catch( e ) {
    122                                         alert("FAIL " + name + " " + num + e);
    123                                         return;
    124                                 }
    125 
    126                                 if ( pos < numTests ) {
    127                                         updateTime();
    128                                         updateTestPos({curID: curID, collection: testNames[curID], version: testVersions[curID]});
    129                                 }
    130 
    131                                 if ( ++pos < numTests ) {
    132                                         setTimeout( arguments.callee, 1 );
    133                                 
    134                                 } else {
    135                                         var data = compute( times, numTests );
    136 
    137                                         data.curID = curID;
    138                                         data.collection = testNames[curID];
    139                                         data.version = testVersions[curID];
    140                                         data.name = title;
    141                                         data.scale = num;
    142                                         data.times = times;
    143                                                                 
    144                                         logTest(data);
    145                         
    146                                         dequeue();
    147                                 }
    148                         }, 1);
    149                 });
    150 
    151                 function compute(times, runs){
    152                         var results = {runs: runs}, num = times.length;
    153 
    154                         times = times.sort(function(a,b){
    155                                 return a - b;
    156                         });
    157 
    158                         // Make Sum
    159                         results.sum = 0;
    160 
    161                         for ( var i = 0; i < num; i++ )
    162                                 results.sum += times[i];
    163 
    164                         // Make Min
    165                         results.min = times[0];
    166                                           
    167                         // Make Max
    168                         results.max = times[ num - 1 ];
    169 
    170                         // Make Mean
    171                         results.mean = results.sum / num;
    172                         
    173                         // Make Median
    174                         results.median = num % 2 == 0 ?
    175                                 (times[Math.floor(num/2)] + times[Math.ceil(num/2)]) / 2 :
    176                                 times[Math.round(num/2)];
    177                         
    178                         // Make Variance
    179                         results.variance = 0;
    180 
    181                         for ( var i = 0; i < num; i++ )
    182                                 results.variance += Math.pow(times[i] - results.mean, 2);
    183 
    184                         results.variance /= num - 1;
    185                                         
    186                         // Make Standard Deviation
    187                         results.deviation = Math.sqrt( results.variance );
    188 
    189                         // Compute Standard Errors Mean
    190                         results.sem = (results.deviation / Math.sqrt(results.runs)) * tDistribution;
    191 
    192                         // Error
    193                         results.error = ((results.sem / results.mean) * 100) || 0;
    194 
    195                         return results;
    196                 }
    197         };
    198         
    199         // All the test data
    200         var tests;
    201         
    202         // The number of test files to load
    203         var totalTests = 0;
    204         var totalTestItems = 0;
    205         
    206         // The number of test files loaded
    207         var numloaded = 0;
    208         
    209         // Queue of functions to run
    210         var queue = [];
    211         var queues = {};
    212 
    213         var catnames = {
    214                 dromaeo: "Dromaeo JavaScript Tests",
    215                 sunspider: "SunSpider JavaScript Tests",
    216                 "v8": "V8 JavaScript Tests",
    217                 dom: "DOM Core Tests",
    218                 jslib: "JavaScript Library Tests",
    219                 cssquery: "CSS Selector Tests"
    220         };
    221 
    222         
    223         var testElems = {};
    224         var testNum = {};
    225         var testDone = {};
    226         var testNames = {};
    227         var testVersions = {};
    228         var dataStore = [];
    229         var names = [];
    230         var interval;
    231         var totalTime = 0;
    232         var time = 0;
    233         var title, testName, testID, testSummary = {} , testSummaryNum = {}, maxTotal = 0, maxTotalNum = 0;
    234         var nameDone = {};
    235         
    236         // Query String Parsing
    237         var search = window.limitSearch || (window.location.search || "?").substr(1);
    238 
    239         search = search.replace(/&runStyle=([^&]+)/, function(all, type){
    240                 runStyle = type;
    241                 return "";
    242         });
    243 
    244         var parts = search.split("&");
    245 
    246         if ( parts[0] === "recommended" ) {
    247                 parts[0] = "dromaeo|sunspider|v8|dom|jslib";
    248         }
    249 
    250         var none = !parts[0] || parts[0].match(/=/);
    251         var filter = parts.length && !parts[0].match(/=/) && parts[0] !== "all" ?
    252                 new RegExp(parts.shift(), "i") :
    253                 /./;
    254 
    255         // To enable shark debugging add &shark to the end of the URL
    256         var doShark = function(name) { return false; };
    257         for ( var i = 0; i < parts.length; i++ ) {
    258                 var m = /^shark(?:=(.*))?$/.exec(parts[i]);
    259                 if (m) {
    260                         if (m[1] === undefined) {
    261                                 doShark = function(name) { return true; };
    262                         }
    263                         else {
    264                                 var sharkMatch = new RegExp(m[1]);
    265                                 doShark = function(name) {
    266                                         return sharkMatch.test(name);
    267                                 };
    268                         }
    269                 }
    270 
    271                 m = /^numTests=(\d+)$/.exec(parts[i]);
    272                 if (m)
    273                         numTests = Number(m[1]);
    274         }
    275 
    276         jQuery(function(){
    277                 var id = search.match(/id=([\d,]+)/);
    278 
    279                 if ( none && !id ) {
    280                         $("#overview").hide();
    281                         return;
    282                 } 
    283 
    284                 var cat = filter.toString().slice(1,-2);
    285 
    286                 if ( catnames[cat] ) {
    287                         $("#overview span:first").html( catnames[cat] );
    288 
    289                         if ( catnames[cat].length > 22 ) {
    290                                 $("#overview span:first").css("font-size", 22);
    291                         }
    292                 }
    293 
    294                 $("#tests").hide();
    295 
    296                 jQuery.getJSON("tests/MANIFEST.json", function(json){
    297                         tests = json;
    298 
    299                         names = [];
    300 
    301                         for ( var name in tests )
    302                                 // Don't load tests that we aren't looking for
    303                                 if ( filter.test( name ) )
    304                                         names.push( name );
    305 
    306                         names = names.sort(function(a, b){
    307                                 return tests[a].name < tests[b].name ?  -1 :
    308                                         tests[a].name == tests[b].name ?  0 : 1;
    309                         });
    310 
    311                         // Check if we're loading a specific result set
    312                         // ?id=NUM
    313                         if ( id ) {
    314                                 jQuery.ajax({
    315                                         url: "store.php?id=" + id[1],
    316                                         dataType: "json",
    317                                         success: function(data){
    318                                                 resultsLoaded(id[1], data);
    319                                         }
    320                                 });
    321 
    322                         // Otherwise we're loading a normal set of tests
    323                         } else {
    324                                 $("#wrapper").append("<br style='clear:both;'/><center><a href='?" + names.join("|") + "'>Re-run tests</a></center>");
    325 
    326                                 for ( var i = 0; i < names.length; i++ ) (function(name){
    327                                         var test = tests[name];
    328 
    329                                         queues[name] = [];
    330                                         makeElem(name);
    331                                         initTest(name);
    332                                         
    333                                         totalTests++;
    334                                         
    335                                         // Check if we're loading an HTML file
    336                                         if ( test.file.match(/html$/) ) {
    337                                                 var iframe = document.createElement("iframe");
    338                                                 iframe.style.height = "1px";
    339                                                 iframe.style.width = "1px";
    340                                                 iframe.src = "tests/" + test.file;
    341                                                 document.body.appendChild( iframe );
    342                                         
    343                                         // Otherwise we're loading a pure-JS test
    344                                         } else {
    345                                                 jQuery.getScript("tests/" + test.file);
    346                                         }
    347                                 })(names[i]);
    348                         }
    349                 });
    350         });
    351 
    352         // Remove the next test from the queue and execute it
    353         function dequeue(){
    354                 if ( interval && queue.length ) {
    355                         if (window.parent) {
    356                                 window.parent.postMessage({ name: "dromaeo:progress",
    357                                                             status: { current: totalTestItems - queue.length,
    358                                                                       score: dataStore[dataStore.length - 1],
    359                                                                       total: totalTestItems } }, "*");
    360                         }
    361                         queue.shift()();
    362                 } else if ( queue.length == 0 ) {
    363                         interval = false;
    364                         time = 0;
    365                         
    366                         $("#overview input").remove();
    367                         updateTimebar();
    368 
    369                         if ( window.limitSearch ) {
    370                                 var summary = (runStyle === "runs/s" ? Math.pow(Math.E, maxTotal / maxTotalNum) : maxTotal).toFixed(2);
    371 
    372                                 if ( typeof tpRecordTime !== "undefined" ) {
    373                                         tpRecordTime( summary );
    374 
    375                                 } else {
    376                                         var pre = document.createElement("pre");
    377                                         pre.style.display = "none";
    378                                         pre.innerHTML = "__start_report" + summary + "__end_report";
    379                                         document.body.appendChild( pre );
    380                                 }
    381 
    382                                 if ( typeof goQuitApplication !== "undefined" ) {
    383                                         goQuitApplication();
    384                                 }
    385         
    386                         } else if ( dataStore && dataStore.length ) {
    387                                 $("body").addClass("alldone");
    388                                 var div = jQuery("<div class='results'>Saving...</div>").insertBefore("#overview");
    389                                 jQuery.ajax({
    390                                         type: "POST",
    391                                         url: "store.php",
    392                                         data: "data=" + encodeURIComponent(JSON.stringify(dataStore)) + "&style=" + runStyle,
    393                                         success: function(id){
    394                                                 var url = window.location.href.replace(/\?.*$/, "") + "?id=" + id;
    395                                                 div.html("Results saved. You can access them at a later time at the following URL:<br/><strong><a href='" + url + "'>" + url + "</a></strong></div>");
    396                                         }
    397                                 });
    398 
    399                                 if (window.parent)
    400                                         window.parent.postMessage({ name: "dromaeo:alldone", result: dataStore }, "*");
    401                         }
    402                 }
    403         }
    404         
    405         function updateTimebar(){
    406                 $("#timebar").html("<span><strong>" + (runStyle === "runs/s" ? Math.pow(Math.E, maxTotal / maxTotalNum) : maxTotal).toFixed(2) + "</strong>" + runStyle + " (Total)</span>");
    407         }
    408         
    409         // Run once all the test files are fully loaded
    410         function init(){
    411                 for ( var n = 0; n < names.length; n++ ) {
    412                         queue = queue.concat( queues[ names[n] ] );
    413                 }
    414 
    415                 totalTestItems = queue.length;
    416                 totalTime = time;
    417                 time += timePerTest;
    418                 updateTime();
    419                 
    420                 $("#pause")
    421                         .val("Run")
    422                         .click(function(){
    423                                 if ( interval ) {
    424                                         interval = null;
    425                                         this.value = "Run";
    426                                 } else {
    427                                         if ( !interval ) {
    428                                                 interval = true;
    429                                                 dequeue();
    430                                         }
    431                                         this.value = "Pause";
    432                                 }
    433                         });
    434 
    435                 if ( window.limitSearch ) {
    436                         $("#pause").click();
    437                 }
    438 
    439                 if (window.parent)
    440                         window.parent.postMessage({ name: "dromaeo:ready" }, "*");
    441         }
    442 
    443         function initTest(curID){
    444                 $("<div class='result-item'></div>")
    445                         .append( testElems[ curID ] )
    446                         .append( "<p>" + (tests[curID] ? tests[ curID ].desc : "") + "<br/><a href='" + 
    447                                 (tests[curID] && tests[curID].origin ? tests[ curID ].origin[1] : "") + "'>Origin</a>, <a href='tests/" +
    448                                 (tests[curID] ? tests[ curID ].file : "") + "'>Source</a>, <b>Tests:</b> " +
    449                                 (tests[curID] && tests[curID].tags ? tests[ curID ].tags.join(", ") : "") + "</p>" )
    450                         .append( "<ol class='results'></ol>" )
    451                         .appendTo("#main");
    452         }
    453         
    454         function resultsLoaded(id, datas){
    455                 var results = {};
    456                 var runs = {};
    457                 var output = "";
    458                 var excluded = [];
    459                 var overview = document.getElementById("overview");
    460 
    461                 for ( var d = 0; d < datas.length; d++ ) {
    462                         var data = datas[d];
    463                         
    464                         runStyle = data.style;
    465 
    466                         if ( datas.length == 1 ) {
    467                                 $("#overview").before("<div class='results'>Viewing test run #" + id +
    468                                         ", run on: " + data.created_at + " by:<br>" + data.useragent + "</div>");
    469                         }
    470 
    471                         runs[data.id] = data;
    472                         runs[data.id].mean = 0;
    473                         runs[data.id].error = 0;
    474                         runs[data.id].num = 0;
    475                         runs[data.id].name = (data.useragent.match(/(MSIE [\d.]+)/) ||
    476                                 data.useragent.match(/((?:WebKit|Firefox|Shiretoko|Opera)\/[\w.]+)/) || [0,data.id])[1];
    477 
    478                         for ( var i = 0; i < data.results.length; i++ ) {
    479                                 var result = data.results[i];
    480                                 var curID = result.collection;
    481                                 var run = result.run_id;
    482                                 
    483                                 result.version += data.style;
    484 
    485                                 if ( !results[curID] )
    486                                         results[curID] = {tests:{}, total:{}, version: result.version};
    487 
    488                                 if ( results[curID].version == result.version ) {
    489                                         if ( !results[curID].total[run] ) {
    490                                                 results[curID].total[run] = {max:0, mean:0, median:0, min:0, deviation:0, error:0, num:0};
    491                                                 results[curID].tests[run] = [];
    492                                         }
    493                                         
    494                                         result.error = ((((result.deviation / Math.sqrt(result.runs)) * tDistribution) / result.mean) * 100) || 0;
    495                                         results[curID].tests[run].push( result );
    496 
    497                                         var error = (parseFloat(result.error) / 100) * parseFloat(result.mean);
    498                                         error = (runStyle === "ms" ? error : error == 0 ? 0 : Math.log(error));
    499                                         var total = results[curID].total[run];
    500                                         total.num++;
    501 
    502                                         for ( var type in total ) {
    503                                                 if ( type == "error" ) {
    504                                                         total.error += error;
    505                                                 } else if ( type == "mean" ) {
    506                                                         total.mean += (runStyle === "ms" ? parseFloat(result.mean) : Math.log(parseFloat(result.mean)));
    507                                                 } else if ( type !== "num" ) {
    508                                                         total[type] += parseFloat(result[type]);
    509                                                 }
    510                                         }
    511                                         
    512                                         runs[run].num++;
    513                                         runs[run].mean += runStyle === "ms" ? parseFloat(result.mean) : Math.log(parseFloat(result.mean));
    514                                         runs[run].error += error;
    515                                 }
    516                         }
    517                 }
    518 
    519                 var runTests = [];
    520 
    521                 if ( datas.length == 1 ) {
    522                         $("body").addClass("alldone");
    523 
    524                         for ( var i = 0; i < data.results.length; i++ ) {
    525                                 var item = data.results[i];
    526                                 var result = item.curID = item.collection;
    527 
    528                                 if ( !filter.test(result) )
    529                                         continue;
    530 
    531                                 if ( !testElems[result] ) {
    532                                         runTests.push(result);
    533                                         makeElem( result );
    534                                         initTest( result );
    535                                 }
    536 
    537                                 // Compute Standard Errors Mean
    538                                 item.sem = (item.deviation / Math.sqrt(item.runs)) * tDistribution;
    539 
    540                                 // Error
    541                                 item.error = ((item.sem / item.mean) * 100) || 0;
    542 
    543                                 logTest( item );
    544 
    545                                 // testDone, testNum, testSummary
    546                                 testDone[ result ] = numTests - 1;
    547                                 testNum[ result ] = 1;
    548 
    549                                 updateTestPos( item );
    550                         }
    551 
    552                         $("div.result-item").addClass("done");
    553 
    554                         totalTime = time = timePerTest;
    555                         updateTime();
    556 
    557                         $("#overview input").remove();
    558                         updateTimebar();
    559                 } else {
    560                         // Remove results where there is only one comparison set
    561                         for ( var id in results ) {
    562                                 var num = 0;
    563                                 
    564                                 for ( var ntest in results[id].tests ) {
    565                                         num++;
    566                                         if ( num > 1 )
    567                                                 break;
    568                                 }
    569                                 
    570                                 if ( num <= 1 ) {
    571                                         excluded.push( id );
    572                                         delete results[id];
    573                                 }
    574                         }
    575                 
    576                         var preoutput = "<tr><td></td>";
    577                         for ( var run in runs )
    578                                 preoutput += "<th><a href='?id=" + run + "'>" + runs[run].name + "</a></th>";
    579                         //preoutput += "<th>Winning %</th></tr>";
    580                         preoutput += "</tr>";
    581 
    582                         for ( var result in results ) {
    583                                 // Skip results that we're filtering out
    584                                 if ( !filter.test(result) )
    585                                         continue;
    586 
    587                                 runTests.push(result);
    588 
    589                                 if ( runStyle === "runs/s" ) {
    590                                         for ( var run in runs ) {
    591                                                 var mean = results[result].total[run].mean - 0;
    592                                                 var error = results[result].total[run].error - 0;
    593 
    594                                                 mean = Math.pow(Math.E, mean / results[result].total[run].num);
    595                                                 error = Math.pow(Math.E, error / results[result].total[run].num);
    596                                                 results[result].total[run].mean = mean;
    597                                                 results[result].total[run].error = error;
    598                                         }
    599                                 }
    600 
    601                                 var name = tests[result] ? tests[result].name : result;
    602                                 var tmp = processWinner(results[result].total);
    603 
    604                                 output += "<tr><th class='name'><span onclick='toggleResults(this.nextSibling);'>&#9654; </span>" +
    605                                         "<a href='' onclick='return toggleResults(this);'>" + name + "</a></th>";
    606 
    607                                 for ( var run in runs ) {
    608                                         var mean = results[result].total[run].mean - 0;
    609                                         var error = results[result].total[run].error - 0;
    610                 
    611                                         output += "<td class='" + (tmp[run] || '') + "'>" + mean.toFixed(2) + "<small>" + runStyle + " &#177;" + ((error / mean) * 100).toFixed(2) + "%</small></td>";
    612                                 }
    613                                 
    614                                 //showWinner(tmp);
    615                                 output += "</tr>";
    616 
    617                                 var _tests = results[result].tests, _data = _tests[run], _num = _data.length;
    618                                 for ( var i = 0; i < _num; i++ ) {
    619                                         output += "<tr class='onetest hidden'><td><small>" + _data[i].name + "</small></td>";
    620                                         for ( var run in runs ) {
    621                                                 output += "<td>" + (_tests[run][i].mean - 0).toFixed(2) + "<small>" + runStyle + " &#177;" + (_tests[run][i].error - 0).toFixed(2) + "%</small></td>";
    622                                         }
    623                                         output += "<td></td></tr>";
    624                                 }
    625                         }
    626 
    627                         if ( runStyle === "runs/s" ) {
    628                                 for ( var run in runs ) {
    629                                         runs[run].mean = Math.pow(Math.E, runs[run].mean / runs[run].num);
    630                                         runs[run].error = Math.pow(Math.E, runs[run].error / runs[run].num);
    631                                 }
    632                         }
    633         
    634                         var tmp = processWinner(runs);
    635                         var totaloutput = "";
    636 
    637                         if ( runStyle === "ms" ) {
    638                                 totaloutput += "<tr><th class='name'>Total:</th>";
    639                         } else {
    640                                 totaloutput += "<tr><th class='name'>Total Score:</th>";
    641                         }
    642 
    643                         for ( var run in runs ) {
    644                                 totaloutput += "<th class='name " + (tmp[run] || '') + "' title='" + (tmp[run + "title"] || '') + "'>" + runs[run].mean.toFixed(2) + "<small>" + runStyle + " &#177;" + ((runs[run].error / runs[run].mean) * 100).toFixed(2) + "%</small></th>";
    645                         }
    646 
    647                         //showWinner(tmp);
    648                         totaloutput += "</tr>";
    649 
    650                         overview.className = "";
    651                         overview.innerHTML = "<div class='resultwrap'><table class='results'>" + preoutput + totaloutput + output + totaloutput + "</table>" + (excluded.length ? "<div style='text-align:left;'><small><b>Excluded Tests:</b> " + excluded.sort().join(", ") + "</small></div>" : "") + "</div>";
    652                 }
    653 
    654                 $("#wrapper").append("<center><a href='?" + runTests.join("|") + "'>Re-run tests</a></center>");
    655                 
    656                 function showWinner(tmp){
    657                         if ( datas.length > 1 ) {
    658                                 if ( tmp.tie )
    659                                         output += "<th>Tie</th>";
    660                                 else
    661                                         output += "<th>" + tmp.diff + "%</th>";
    662                         }
    663                 }
    664         }
    665 
    666         this.toggleResults = function(elem){
    667                 var span = elem.previousSibling;
    668 
    669                 elem.blur();
    670                 elem = elem.parentNode.parentNode.nextSibling;
    671 
    672                 span.innerHTML = elem.className.indexOf("hidden") < 0 ? "&#9654; " : "&#9660; ";
    673 
    674                 while ( elem && elem.className.indexOf("onetest") >= 0 ) {
    675                         elem.className = "onetest" + (elem.className.indexOf("hidden") >= 0 ? " " : " hidden");
    676                         elem = elem.nextSibling;
    677                 }
    678 
    679                 return false;
    680         };
    681 
    682         function updateTime(){
    683                 time -= timePerTest;
    684                 $("#left").html(Math.floor(time / 60) + ":" + (time % 60 < 10 ? "0" : "" ) + Math.floor(time % 60));
    685 
    686                 var w = ((totalTime - time) / totalTime) * 100;
    687 
    688                 $("#timebar").width((w < 1 ? 1 : w) + "%");
    689         }
    690         
    691         function logTest(data){
    692                 // Keep a running summary going
    693                 data.mean = parseFloat(data.mean);
    694                 var mean = (runStyle === "runs/s" ? Math.log(data.mean) : data.mean);
    695                 testSummary[data.curID] = (testSummary[data.curID] || 0) + mean;
    696                 testSummaryNum[data.curID] = (testSummaryNum[data.curID] || 0) + 1;
    697                 
    698                 maxTotal += mean;
    699                 maxTotalNum++;
    700 
    701                 testDone[data.curID]--;
    702                 updateTestPos(data);
    703 
    704                 testElems[data.curID].next().next().append("<li><b>" + data.name + 
    705                         ":</b> " + data.mean.toFixed(2) + "<small>" + runStyle + " &#177;" + data.error.toFixed(2) + "%</small></li>");
    706 
    707                 dataStore.push(data);
    708         }
    709 
    710         function updateTestPos(data, update){
    711                 if ( !update )
    712                         testDone[data.curID]++;
    713 
    714                 var per = (testDone[data.curID] / (testNum[data.curID] * numTests)) * 100;
    715 
    716                 if ( update )
    717                         per = 1;
    718                 
    719                 var mean = (runStyle === "runs/s" ?
    720                         Math.pow(Math.E, testSummary[data.curID] / testSummaryNum[data.curID]) :
    721                         testSummary[data.curID]);
    722 
    723                 testElems[data.curID].html("<b>" + (tests[data.curID] ? tests[data.curID].name : data.curID) +
    724                         ":</b> <div class='bar'><div style='width:" +
    725                         per + "%;'>" + (per >= 100 ? "<span>" + mean.toFixed(2) + runStyle + "</span>" : "") + "</div></div>");
    726 
    727                 if ( per >= 100 && testSummary[data.curID] > 0 ) {
    728                         testElems[data.curID].parent().addClass("done");
    729                 }
    730         }
    731         
    732         function processWinner(data){
    733                 var minVal = -1, min2Val = -1, min, min2;
    734 
    735                 for ( var i in data ) {
    736                         var total = data[i].mean;
    737                         if ( minVal == -1 || (runStyle === "ms" && total <= minVal || runStyle === "runs/s" && total >= minVal) ) {
    738                                 min2Val = minVal;
    739                                 min2 = min;
    740                                 minVal = total;
    741                                 min = i;
    742                         } else if ( min2Val == -1 || (runStyle === "ms" && total <= minVal || runStyle === "runs/s" && total >= min2Val) ) {
    743                                 min2Val = total;
    744                                 min2 = i;
    745                         }
    746                 }
    747 
    748                 var tieVal = (runStyle === "ms" ? minVal : min2Val) + data[min].error + data[min2].error;
    749 
    750                 var ret = {
    751                         winner: min,
    752                         diff: runStyle === "ms" ?
    753                                 -1 * Math.round((1 - (min2Val / minVal)) * 100) :
    754                                 Math.round(((minVal / min2Val) - 1) * 100),
    755                         tie: minVal == min2Val || (runStyle === "ms" ? tieVal >= min2Val : tieVal >= minVal)
    756                 };
    757 
    758                 ret.tie = ret.tie || ret.diff == 0;
    759 
    760                 if ( ret.tie ) {
    761                         ret[ min ] = 'tie';
    762                         ret[ min2 ] = 'tie';
    763                         ret[ min + 'title' ] = "Tied with another run.";
    764                         ret[ min2 + 'title' ] = "Tied with another run.";
    765                 } else {
    766                         ret[ min ] = 'winner';
    767                         if ( min2Val > -1 ) {
    768                                 ret[ min + 'title' ] = "Won by " + ret.diff + "%.";
    769                         }
    770                 }
    771 
    772                 return ret;
    773         }
    774         
    775         function makeElem(testID){
    776 /*
    777                 if ( tests[testID] ) {
    778                         var cat = tests[testID].category, catsm = cat.replace(/[^\w]/g, "-");
    779                         if ( !$("#" + catsm).length ) {
    780                                 $("#main").append("<h2 id='" + catsm + "' class='test'><a href='?cat=" + cat +"'>" + cat + '</a><div class="bar"><div id="timebar" style="width:25%;"><span class="left">Est.&nbsp;Time:&nbsp;<strong id="left">0:00</strong></span></div></div>');
    781                         }
    782                 }
    783 */
    784                 
    785                 testElems[testID] = $("<div class='test'></div>")
    786                         .click(function(){
    787                                 var next = jQuery(this).next().next();
    788                                 if ( next.children().length == 0 ) return;
    789                                 var display = next.css("display");
    790                                 next.css("display", display == 'none' ? 'block' : 'none');
    791                         });
    792 
    793                 updateTestPos({curID: testID, collection: tests[testID] ? tests[testID].name : testID, version: testVersions[testID]}, true);
    794         }
    795 
    796         window.addEventListener("message", function(event) {
    797                 switch (event.data.name) {
    798                 case "dromaeo:start":
    799                         $("#pause").click();
    800                         break;
    801                 default:
    802                         console.log("Unknwon message:" + JSON.stringify(event.data));
    803                         break;
    804                 }
    805 });
    806 })();
    807