r3199 committed - Spinner: Merged in trunk r3000:3198.

r3199 committed - Spinner: Merged in trunk r3000:3198.

Revision: 3199
Author: scott.gonzalez
Date: Sun Sep 6 09:42:50 2009
Log: Spinner: Merged in trunk r3000:3198.
http://code.google.com/p/jquery-ui/source/detail?r=3199
Added:
/branches/dev/spinner/demos/datepicker/show-week.html
/branches/dev/spinner/demos/tabs/bottom.html
/branches/dev/spinner/external/testrunner-r6416.js
/branches/dev/spinner/tests/jquery.simulate.js
/branches/dev/spinner/tests/unit/all.html
/branches/dev/spinner/tests/unit/all_2.html
/branches/dev/spinner/tests/unit/tabs/data

/branches/dev/spinner/tests/visual/accordion/accordion_option_fillSpace_true.html

/branches/dev/spinner/tests/visual/accordion/accordion_option_navigation_true.html
/branches/dev/spinner/tests/visual/accordion/accordion_ticket_4322.html
/branches/dev/spinner/tests/visual/accordion/accordion_ticket_4444.html
/branches/dev/spinner/tests/visual/slider/slider_option_animate_false.html
/branches/dev/spinner/tests/visual/slider/slider_option_animate_true.html
/branches/dev/spinner/tests/visual/slider/slider_option_max_3.html
/branches/dev/spinner/tests/visual/slider/slider_option_max_30.html
/branches/dev/spinner/tests/visual/slider/slider_option_max_300.html
/branches/dev/spinner/tests/visual/slider/slider_option_min_-3.html
/branches/dev/spinner/tests/visual/slider/slider_option_min_-30.html
/branches/dev/spinner/tests/visual/slider/slider_option_min_-300.html

/branches/dev/spinner/tests/visual/slider/slider_option_orientation_horizontal.html

/branches/dev/spinner/tests/visual/slider/slider_option_orientation_vertical.html
/branches/dev/spinner/tests/visual/slider/slider_option_range_false.html
/branches/dev/spinner/tests/visual/slider/slider_option_range_max.html
/branches/dev/spinner/tests/visual/slider/slider_option_range_min.html
/branches/dev/spinner/tests/visual/slider/slider_option_range_true.html
/branches/dev/spinner/tests/visual/slider/slider_option_step_25.html
/branches/dev/spinner/tests/visual/slider/slider_option_step_5.html
/branches/dev/spinner/tests/visual/slider/slider_option_value_3.html
/branches/dev/spinner/tests/visual/slider/slider_option_value_30.html

/branches/dev/spinner/tests/visual/slider/slider_option_values_25_50_75.html
/branches/dev/spinner/tests/visual/slider/slider_option_values_25_75.html
/branches/dev/spinner/tests/visual/slider/slider_option_values_50.html
Deleted:
/branches/dev/spinner/external/jquery.simulate-r6163.js
/branches/dev/spinner/external/testrunner-r6343.js
/branches/dev/spinner/tests/unit/all
/branches/dev/spinner/tests/unit/tabs/test.html
Modified:
/branches/dev/spinner/build/build.xml
/branches/dev/spinner/demos/accordion/sortable.html
/branches/dev/spinner/demos/datepicker/index.html
/branches/dev/spinner/demos/dialog/animated.html
/branches/dev/spinner/demos/dialog/default.html
/branches/dev/spinner/demos/dialog/modal-confirmation.html
/branches/dev/spinner/demos/dialog/modal-form.html
/branches/dev/spinner/demos/dialog/modal-message.html
/branches/dev/spinner/demos/dialog/modal.html
/branches/dev/spinner/demos/effect/easing.html
/branches/dev/spinner/demos/index.html
/branches/dev/spinner/demos/position/default.html
/branches/dev/spinner/demos/tabs/index.html
/branches/dev/spinner/tests/unit/accordion/accordion.html
/branches/dev/spinner/tests/unit/accordion/accordion_options.js
/branches/dev/spinner/tests/unit/core/core.html
/branches/dev/spinner/tests/unit/core/core.js
/branches/dev/spinner/tests/unit/core/selector.js
/branches/dev/spinner/tests/unit/datepicker/datepicker.html
/branches/dev/spinner/tests/unit/defaults.html
/branches/dev/spinner/tests/unit/dialog/dialog.html
/branches/dev/spinner/tests/unit/draggable/draggable.html
/branches/dev/spinner/tests/unit/draggable/draggable_options.js
/branches/dev/spinner/tests/unit/droppable/droppable.html
/branches/dev/spinner/tests/unit/index.html
/branches/dev/spinner/tests/unit/position/position.html
/branches/dev/spinner/tests/unit/progressbar/progressbar.html
/branches/dev/spinner/tests/unit/resizable/resizable.html
/branches/dev/spinner/tests/unit/selectable/selectable.html
/branches/dev/spinner/tests/unit/slider/slider.html
/branches/dev/spinner/tests/unit/sortable/sortable.html
/branches/dev/spinner/tests/unit/spinner/spinner.html
/branches/dev/spinner/tests/unit/tabs/tabs.html
/branches/dev/spinner/tests/visual/dialog/default.html
/branches/dev/spinner/tests/visual/dialog/dialog.html

/branches/dev/spinner/tests/visual/dialog/dialog_on_page_with_large_dom.html

/branches/dev/spinner/tests/visual/dialog/dialog_on_page_with_scrollbars.html

/branches/dev/spinner/tests/visual/dialog/dialog_option_closeOnEscape_false.html

/branches/dev/spinner/tests/visual/dialog/dialog_option_closeOnEscape_true.html
/branches/dev/spinner/tests/visual/dialog/dialog_option_modal_false.html
/branches/dev/spinner/tests/visual/dialog/dialog_option_modal_true.html
/branches/dev/spinner/themes/base/ui.accordion.css
/branches/dev/spinner/themes/base/ui.dialog.css
/branches/dev/spinner/themes/base/ui.theme.css
/branches/dev/spinner/ui/i18n/ui.datepicker-ar.js
/branches/dev/spinner/ui/i18n/ui.datepicker-az.js
/branches/dev/spinner/ui/i18n/ui.datepicker-bg.js
/branches/dev/spinner/ui/i18n/ui.datepicker-ca.js
/branches/dev/spinner/ui/i18n/ui.datepicker-cs.js
/branches/dev/spinner/ui/i18n/ui.datepicker-da.js
/branches/dev/spinner/ui/i18n/ui.datepicker-de.js
/branches/dev/spinner/ui/i18n/ui.datepicker-el.js
/branches/dev/spinner/ui/i18n/ui.datepicker-eo.js
/branches/dev/spinner/ui/i18n/ui.datepicker-es.js
/branches/dev/spinner/ui/i18n/ui.datepicker-et.js
/branches/dev/spinner/ui/i18n/ui.datepicker-eu.js
/branches/dev/spinner/ui/i18n/ui.datepicker-fa.js
/branches/dev/spinner/ui/i18n/ui.datepicker-fi.js
/branches/dev/spinner/ui/i18n/ui.datepicker-fr-CH.js
/branches/dev/spinner/ui/i18n/ui.datepicker-fr.js
/branches/dev/spinner/ui/i18n/ui.datepicker-he.js
/branches/dev/spinner/ui/i18n/ui.datepicker-hr.js
/branches/dev/spinner/ui/i18n/ui.datepicker-hu.js
/branches/dev/spinner/ui/i18n/ui.datepicker-hy.js
/branches/dev/spinner/ui/i18n/ui.datepicker-id.js
/branches/dev/spinner/ui/i18n/ui.datepicker-is.js
/branches/dev/spinner/ui/i18n/ui.datepicker-it.js
/branches/dev/spinner/ui/i18n/ui.datepicker-ja.js
/branches/dev/spinner/ui/i18n/ui.datepicker-ko.js
/branches/dev/spinner/ui/i18n/ui.datepicker-lt.js
/branches/dev/spinner/ui/i18n/ui.datepicker-lv.js
/branches/dev/spinner/ui/i18n/ui.datepicker-ms.js
/branches/dev/spinner/ui/i18n/ui.datepicker-nl.js
/branches/dev/spinner/ui/i18n/ui.datepicker-no.js
/branches/dev/spinner/ui/i18n/ui.datepicker-pl.js
/branches/dev/spinner/ui/i18n/ui.datepicker-pt-BR.js
/branches/dev/spinner/ui/i18n/ui.datepicker-ro.js
/branches/dev/spinner/ui/i18n/ui.datepicker-ru.js
/branches/dev/spinner/ui/i18n/ui.datepicker-sk.js
/branches/dev/spinner/ui/i18n/ui.datepicker-sl.js
/branches/dev/spinner/ui/i18n/ui.datepicker-sq.js
/branches/dev/spinner/ui/i18n/ui.datepicker-sr-SR.js
/branches/dev/spinner/ui/i18n/ui.datepicker-sr.js
/branches/dev/spinner/ui/i18n/ui.datepicker-sv.js
/branches/dev/spinner/ui/i18n/ui.datepicker-th.js
/branches/dev/spinner/ui/i18n/ui.datepicker-tr.js
/branches/dev/spinner/ui/i18n/ui.datepicker-uk.js
/branches/dev/spinner/ui/i18n/ui.datepicker-vi.js
/branches/dev/spinner/ui/i18n/ui.datepicker-zh-CN.js
/branches/dev/spinner/ui/i18n/ui.datepicker-zh-TW.js
/branches/dev/spinner/ui/ui.accordion.js
/branches/dev/spinner/ui/ui.core.js
/branches/dev/spinner/ui/ui.datepicker.js
/branches/dev/spinner/ui/ui.dialog.js
/branches/dev/spinner/ui/ui.draggable.js
/branches/dev/spinner/ui/ui.droppable.js
/branches/dev/spinner/ui/ui.position.js
/branches/dev/spinner/ui/ui.resizable.js
/branches/dev/spinner/ui/ui.slider.js
/branches/dev/spinner/ui/ui.sortable.js
Replaced:
/branches/dev/spinner/tests/unit/tabs/data/test.html
=======================================
--- /dev/null
+++ /branches/dev/spinner/demos/datepicker/show-week.html    Sun Sep 6
09:42:50 2009
@@ -0,0 +1,34 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <title>jQuery UI Datepicker - Show week of the year</title>
+    <link type="text/css" href="../../themes/base/ui.all.css"
rel="stylesheet" />
+    <script type="text/javascript" src="../../jquery-1.3.2.js"></script>
+    <script type="text/javascript" src="../../ui/ui.core.js"></script>
+    <script type="text/javascript" src="../../ui/ui.datepicker.js"></script>
+    <link type="text/css" href="../demos.css" rel="stylesheet" />
+    <script type="text/javascript">
+    $(function() {
+        $("#datepicker").datepicker({showWeek: true, firstDay: 1});
+    });
+    </script>
+</head>
+<body>
+
+<div class="demo">
+
+

Date: <input type="text" id="datepicker">


+
+</div><!-- End demo -->
+
+<div class="demo-description">
+
+

The datepicker can show the week of the year. The default calculation
follows
+    the ISO 8601 definition: the week starts on Monday, the first week of the
year
+    contains the first Thursday of the year. This means that some days from
one
+    year may be placed into weeks 'belonging' to another year.






+
+</div><!-- End demo-description -->
+
+</body>
+</html>
=======================================
--- /dev/null
+++ /branches/dev/spinner/demos/tabs/bottom.html    Sun Sep 6 09:42:50 2009
@@ -0,0 +1,58 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <title>jQuery UI Tabs - Tabs at bottom</title>
+    <link type="text/css" href="../../themes/base/ui.all.css"
rel="stylesheet" />
+    <script type="text/javascript" src="../../jquery-1.3.2.js"></script>
+    <script type="text/javascript" src="../../ui/ui.core.js"></script>
+    <script type="text/javascript" src="../../ui/ui.tabs.js"></script>
+    <link type="text/css" href="../demos.css" rel="stylesheet" />
+    <script type="text/javascript">
+    $(function() {
+        $("#tabs").tabs();
+        $(".tabs-bottom .ui-tabs-nav, .tabs-bottom .ui-tabs-nav > *")
+         .removeClass("ui-corner-all ui-corner-top")
+         .addClass("ui-corner-bottom");
+    });
+    </script>
+    <style>
+        #tabs { height: 200px; }
+        .tabs-bottom { position: relative; }
+        .tabs-bottom .ui-tabs-panel { height: 140px; overflow: auto; }
+        .tabs-bottom .ui-tabs-nav { position: absolute !important; left: 0;
bottom: 0; right:0; padding: 0 0.2em 0.2em 0; }
+        .tabs-bottom .ui-tabs-nav li { margin-top: -2px !important;
margin-bottom: 1px !important; border-top: none; border-bottom-width: 1px; }
+        .ui-tabs-selected { margin-top: -3px !important; }
+    </style>
+</head>
+<body>
+
+<div class="demo">
+
+<div id="tabs" class="tabs-bottom">
+    <ul>
+        <li><a href="#tabs-1">Nunc tincidunt</a></li>
+        <li><a href="#tabs-2">Proin dolor</a></li>
+        <li><a href="#tabs-3">Aenean lacinia</a></li>
+    </ul>
+    <div id="tabs-1">
+        

Proin elit arcu, rutrum commodo, vehicula tempus, commodo a, risus.
Curabitur nec arcu. Donec sollicitudin mi sit amet mauris. Nam elementum
quam ullamcorper ante. Etiam aliquet massa et lorem. Mauris dapibus lacus
auctor risus. Aenean tempor ullamcorper leo. Vivamus sed magna quis ligula
eleifend adipiscing. Duis orci. Aliquam sodales tortor vitae ipsum. Aliquam
nulla. Duis aliquam molestie erat. Ut et mauris vel pede varius
sollicitudin. Sed ut dolor nec orci tincidunt interdum. Phasellus ipsum.
Nunc tristique tempus lectus.







+    </div>
+    <div id="tabs-2">
+        

Morbi tincidunt, dui sit amet facilisis feugiat, odio metus gravida
ante, ut pharetra massa metus id nunc. Duis scelerisque molestie turpis.
Sed fringilla, massa eget luctus malesuada, metus eros molestie lectus, ut
tempus eros massa ut dolor. Aenean aliquet fringilla sem. Suspendisse sed
ligula in ligula suscipit aliquam. Praesent in eros vestibulum mi
adipiscing adipiscing. Morbi facilisis. Curabitur ornare consequat nunc.
Aenean vel metus. Ut posuere viverra nulla. Aliquam erat volutpat.
Pellentesque convallis. Maecenas feugiat, tellus pellentesque pretium
posuere, felis lorem euismod felis, eu ornare leo nisi vel felis. Mauris
consectetur tortor et purus.









+    </div>
+    <div id="tabs-3">
+        

Mauris eleifend est et turpis. Duis id erat. Suspendisse potenti.
Aliquam vulputate, pede vel vehicula accumsan, mi neque rutrum erat, eu
congue orci lorem eget lorem. Vestibulum non ante. Class aptent taciti
sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
Fusce sodales. Quisque eu urna vel enim commodo pellentesque. Praesent eu
risus hendrerit ligula tempus pretium. Curabitur lorem enim, pretium nec,
feugiat nec, luctus a, lacus.






+        

Duis cursus. Maecenas ligula eros, blandit nec, pharetra at, semper
at, magna. Nullam ac lacus. Nulla facilisi. Praesent viverra justo vitae
neque. Praesent blandit adipiscing velit. Suspendisse potenti. Donec
mattis, pede vel pharetra blandit, magna ligula faucibus eros, id euismod
lacus dolor eget odio. Nam scelerisque. Donec non libero sed nulla mattis
commodo. Ut sagittis. Donec nisi lectus, feugiat porttitor, tempor ac,
tempor vitae, pede. Aenean vehicula velit eu tellus interdum rutrum.
Maecenas commodo. Pellentesque nec elit. Fusce in lacus. Vivamus a libero
vitae lectus hendrerit hendrerit.








+    </div>
+</div>
+
+</div><!-- End demo -->
+
+<div class="demo-description">
+
+

With some additional CSS (for positioning) and JS (to put the right
classes on elements) the tabs can be placed below their content.


+
+</div><!-- End demo-description -->
+
+</body>
+</html>
=======================================
--- /dev/null
+++ /branches/dev/spinner/external/testrunner-r6416.js    Sun Sep 6 09:42:50
2009
@@ -0,0 +1,803 @@
+/*
+ * QUnit - jQuery unit testrunner
+ *
+ * http://docs.jquery.com/QUnit
+ *
+ * Copyright (c) 2008 John Resig, Jörn Zaefferer
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * $Id: testrunner.js 6416 2009-07-10 16:08:27Z joern.zaefferer $
+ */
+
+(function($) {
+
+// Test for equality any JavaScript type.
+// Discussions and reference: http://philrathe.com/articles/equiv
+// Test suites: http://philrathe.com/tests/equiv
+// Author: Philippe Rathé <prathe@gmail.com>
+var equiv = function () {
+
+ var innerEquiv; // the real equiv function
+ var callers = []; // stack to decide between skip/abort functions
+
+
+ // Determine what is o.
+ function hoozit(o) {
+ if (o.constructor === String) {
+ return "string";
+
+ } else if (o.constructor === Boolean) {
+ return "boolean";
+
+ } else if (o.constructor === Number) {
+
+ if (isNaN(o)) {
+ return "nan";
+ } else {
+ return "number";
+ }
+
+ } else if (typeof o === "undefined") {
+ return "undefined";
+
+ // consider: typeof null === object
+ } else if (o === null) {
+ return "null";
+
+ // consider: typeof [] === object
+ } else if (o instanceof Array) {
+ return "array";
+
+ // consider: typeof new Date() === object
+ } else if (o instanceof Date) {
+ return "date";
+
+ // consider: /./ instanceof Object;
+ // /./ instanceof RegExp;
+ // typeof /./ === "function"; // => false in IE and Opera,
+ // true in FF and Safari
+ } else if (o instanceof RegExp) {
+ return "regexp";
+
+ } else if (typeof o === "object") {
+ return "object";
+
+ } else if (o instanceof Function) {
+ return "function";
+ } else {
+ return undefined;
+ }
+ }
+
+ // Call the o related callback with the given arguments.
+ function bindCallbacks(o, callbacks, args) {
+ var prop = hoozit(o);
+ if (prop) {
+ if (hoozit(callbacks[prop]) === "function") {
+ return callbacks[prop].apply(callbacks, args);
+ } else {
+ return callbacks[prop]; // or undefined
+ }
+ }
+ }
+
+ var callbacks = function () {
+
+ // for string, boolean, number and null
+ function useStrictEquality(b, a) {
+ if (b instanceof a.constructor || a instanceof b.constructor) {
+ // to catch short annotaion VS 'new' annotation of a
declaration
+ // e.g. var i = 1;
+ // var j = new Number(1);
+ return a == b;
+ } else {
+ return a === b;
+ }
+ }
+
+ return {
+ "string": useStrictEquality,
+ "boolean": useStrictEquality,
+ "number": useStrictEquality,
+ "null": useStrictEquality,
+ "undefined": useStrictEquality,
+
+ "nan": function (b) {
+ return isNaN(b);
+ },
+
+ "date": function (b, a) {
+ return hoozit(b) === "date" && a.valueOf() === b.valueOf();
+ },
+
+ "regexp": function (b, a) {
+ return hoozit(b) === "regexp" &&
+ a.source === b.source && // the regex itself
+ a.global === b.global && // and its modifers (gmi) ...
+ a.ignoreCase === b.ignoreCase &&
+ a.multiline === b.multiline;
+ },
+
+ // - skip when the property is a method of an instance (OOP)
+ // - abort otherwise,
+ // initial === would have catch identical references anyway
+ "function": function () {
+ var caller = callers[callers.length - 1];
+ return caller !== Object &&
+ typeof caller !== "undefined";
+ },
+
+ "array": function (b, a) {
+ var i;
+ var len;
+
+ // b could be an object literal here
+ if ( ! (hoozit(b) === "array")) {
+ return false;
+ }
+
+ len = a.length;
+ if (len !== b.length) { // safe and faster
+ return false;
+ }
+ for (i = 0; i < len; i++) {
+ if( ! innerEquiv(a[i], b[i])) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ "object": function (b, a) {
+ var i;
+ var eq = true; // unless we can proove it
+ var aProperties = [], bProperties = []; // collection of
strings
+
+ // comparing constructors is more strict than using
instanceof
+ if ( a.constructor !== b.constructor) {
+ return false;
+ }
+
+ // stack constructor before traversing properties
+ callers.push(a.constructor);
+
+ for (i in a) { // be strict: don't ensures hasOwnProperty
and go deep
+
+ aProperties.push(i); // collect a's properties
+
+ if ( ! innerEquiv(a[i], b[i])) {
+ eq = false;
+ }
+ }
+
+ callers.pop(); // unstack, we are done
+
+ for (i in b) {
+ bProperties.push(i); // collect b's properties
+ }
+
+ // Ensures identical properties name
+ return eq && innerEquiv(aProperties.sort(),
bProperties.sort());
+ }
+ };
+ }();
+
+ innerEquiv = function () { // can take multiple arguments
+ var args = Array.prototype.slice.apply(arguments);
+ if (args.length < 2) {
+ return true; // end transition
+ }
+
+ return (function (a, b) {
+ if (a === b) {
+ return true; // catch the most you can
+ } else if (a === null || b === null || typeof a
=== "undefined" || typeof b === "undefined" || hoozit(a) !== hoozit(b)) {
+ return false; // don't lose time with error prone cases
+ } else {
+ return bindCallbacks(a, callbacks, [b, a]);
+ }
+
+ // apply transition with (1..n) arguments
+ })(args[0], args[1]) && arguments.callee.apply(this,
args.splice(1, args.length -1));
+ };
+
+ return innerEquiv;
+
+}();
+
+var GETParams = $.map( location.search.slice(1).split('&'),
decodeURIComponent ),
+    ngindex = $.inArray("noglobals", GETParams),
+    noglobals = ngindex !== -1;
+
+if( noglobals )
+    GETParams.splice( ngindex, 1 );
+
+var config = {
+    stats: {
+        all: 0,
+        bad: 0
+    },
+    queue: [],
+    // block until document ready
+    blocking: true,
+    //restrict modules/tests by get parameters
+    filters: GETParams,
+    isLocal: !!(window.location.protocol == 'file:')
+};
+
+// public API as global methods
+$.extend(window, {
+    test: test,
+    module: module,
+    expect: expect,
+    ok: ok,
+    equals: equals,
+    start: start,
+    stop: stop,
+    reset: reset,
+    isLocal: config.isLocal,
+    same: function(a, b, message) {
+        push(equiv(a, b), a, b, message);
+    },
+    QUnit: {
+        equiv: equiv,
+        ok: ok,
+        done: function(failures, total){},
+        log: function(result, message){}
+    },
+    // legacy methods below
+    isSet: isSet,
+    isObj: isObj,
+    compare: function() {
+        throw "compare is deprecated - use same() instead";
+    },
+    compare2: function() {
+        throw "compare2 is deprecated - use same() instead";
+    },
+    serialArray: function() {
+        throw "serialArray is deprecated - use jsDump.parse() instead";
+    },
+    q: q,
+    t: t,
+    url: url,
+    triggerEvent: triggerEvent
+});
+
+$(window).load(function() {
+
+    if (!$("#header, #banner, #userAgent, #tests").length) {
+        $('body').prepend(
+            '<h1 id="header">' + document.title + '</h1>' +
+            '<h2 id="banner"></h2>' +
+            '<h2 id="userAgent"></h2>' +
+            '<ol id="tests"></ol>'
+        );
+    }
+
+    $('#userAgent').html(navigator.userAgent);
+    var head = $('<div class="testrunner-toolbar"><label
for="filter-pass">Hide passed
tests</label></div>').insertAfter("#userAgent");
+    $('<input type="checkbox" id="filter-pass" />').attr("disabled",
true).prependTo(head).click(function() {
+        $('li.pass')[this.checked ? 'hide' : 'show']();
+    });
+    $('<input type="checkbox" id="filter-missing">').attr("disabled",
true).appendTo(head).click(function() {
+        $("li.fail:contains('missing test - untested code is broken
code')").parent('ol').parent('li.fail')[this.checked ? 'hide' : 'show']();
+    });
+    $("#filter-missing").after('<label for="filter-missing">Hide missing
tests (untested code is broken code)</label>');
+    runTest();
+});
+
+function synchronize(callback) {
+    config.queue.push(callback);
+    if(!config.blocking) {
+        process();
+    }
+}
+
+function process() {
+    while(config.queue.length && !config.blocking) {
+        config.queue.shift()();
+    }
+}
+
+function stop(timeout) {
+    config.blocking = true;
+    if (timeout)
+        config.timeout = setTimeout(function() {
+            QUnit.ok( false, "Test timed out" );
+            start();
+        }, timeout);
+}
+function start() {
+    // A slight delay, to avoid any current callbacks
+    setTimeout(function() {
+        if(config.timeout)
+            clearTimeout(config.timeout);
+        config.blocking = false;
+        process();
+    }, 13);
+}
+
+function validTest( name ) {
+    var i = config.filters.length,
+        run = false;
+
+    if( !i )
+        return true;
+
+    while( i-- ){
+        var filter = config.filters[i],
+            not = filter.charAt(0) == '!';
+        if( not )
+            filter = filter.slice(1);
+        if( name.indexOf(filter) != -1 )
+            return !not;
+        if( not )
+            run = true;
+    }
+    return run;
+}
+
+function runTest() {
+    config.blocking = false;
+    var started = +new Date;
+    config.fixture = document.getElementById('main').innerHTML;
+    config.ajaxSettings = $.ajaxSettings;
+    synchronize(function() {
+        $('<p id="testresult" class="result"/>').html(['Tests completed in ',
+            +new Date - started, ' milliseconds.<br/>',
+            '<span class="bad">', config.stats.all - config.stats.bad, '</span>
tests of <span class="all">', config.stats.all, '</span> passed, ',
config.stats.bad,' failed.']
+            .join(''))
+            .appendTo("body");
+        $("#banner").addClass(config.stats.bad ? "fail" : "pass");
+        QUnit.done( config.stats.bad, config.stats.all );
+    });
+}
+
+var pollution;
+
+function saveGlobal(){
+    pollution = [ ];
+
+    if( noglobals )
+        for( var key in window )
+            pollution.push(key);
+}
+function checkPollution( name ){
+    var old = pollution;
+    saveGlobal();
+
+    if( pollution.length > old.length ){
+        ok( false, "Introduced global variable(s): " + diff(old,
pollution).join(", ") );
+        config.expected++;
+    }
+}
+
+function diff( clean, dirty ){
+    return $.grep( dirty, function(name){
+        return $.inArray( name, clean ) == -1;
+    });
+}
+
+function test(name, callback) {
+    if(config.currentModule)
+        name = config.currentModule + " module: <span>" + name + "</span>";
+    var lifecycle = $.extend({
+        setup: function() {},
+        teardown: function() {}
+    }, config.moduleLifecycle);
+
+    if ( !validTest(name) )
+        return;
+
+    var testEnvironment = {};
+
+    synchronize(function() {
+        config.assertions = [];
+        config.expected = null;
+        try {
+            if( !pollution )
+                saveGlobal();
+            lifecycle.setup.call(testEnvironment);
+        } catch(e) {
+            QUnit.ok( false, "Setup failed on " + name + ": " + e.message );
+        }
+    });
+    synchronize(function() {
+        try {
+            callback.call(testEnvironment);
+        } catch(e) {
+            fail("Test " + name + " died, exception and test follows", e, callback);
+            QUnit.ok( false, "Died on test #" + (config.assertions.length + 1)
+ ": " + e.message );
+            // else next test will carry the responsibility
+            saveGlobal();
+        }
+    });
+    synchronize(function() {
+        try {
+            checkPollution();
+            lifecycle.teardown.call(testEnvironment);
+        } catch(e) {
+            QUnit.ok( false, "Teardown failed on " + name + ": " + e.message );
+        }
+    });
+    synchronize(function() {
+        try {
+            reset();
+        } catch(e) {
+            fail("reset() failed, following Test " + name + ", exception and reset
fn follows", e, reset);
+        }
+
+        if(config.expected && config.expected != config.assertions.length) {
+            QUnit.ok( false, "Expected " + config.expected + " assertions, but " +
config.assertions.length + " were run" );
+        }
+
+        var good = 0, bad = 0;
+        var ol = $("<ol/>").hide();
+        config.stats.all += config.assertions.length;
+        for ( var i = 0; i < config.assertions.length; i++ ) {
+            var assertion = config.assertions[i];
+            
$("<li/>").addClass(assertion.result ? "pass" : "fail").text(assertion.message
|| "(no message)").appendTo(ol);
+         &n