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