text: QUnit.urlParams = urlParams;
  
  // Figure out if we're running the tests from a server or not
  QUnit.isLocal = !( defined.document && window.location.protocol !== "file:" );
  
  // Expose the current QUnit version
  QUnit.version = "@VERSION";
  
  extend( QUnit, {
  
  	// call on start of module test to prepend name to all tests
  	module: function( name, testEnvironment, executeNow ) {
  		var module, moduleFns;
  		var currentModule = config.currentModule;
  
  		if ( arguments.length === 2 ) {
  			if ( testEnvironment instanceof Function ) {
  				executeNow = testEnvironment;
  				testEnvironment = undefined;
  			}
  		}
  
  		// DEPRECATED: handles setup/teardown functions,
  		// beforeEach and afterEach should be used instead
  		if ( testEnvironment && testEnvironment.setup ) {
  			testEnvironment.beforeEach = testEnvironment.setup;
  			delete testEnvironment.setup;
  		}
  		if ( testEnvironment && testEnvironment.teardown ) {
  			testEnvironment.afterEach = testEnvironment.teardown;
  			delete testEnvironment.teardown;
  		}
  
  		module = createModule();
  
  		moduleFns = {
  			beforeEach: setHook( module, "beforeEach" ),
  			afterEach: setHook( module, "afterEach" )
  		};
  
  		if ( executeNow instanceof Function ) {
  			config.moduleStack.push( module );
  			setCurrentModule( module );
  			executeNow.call( module.testEnvironment, moduleFns );
  			config.moduleStack.pop();
  			module = module.parentModule || currentModule;
  		}
  
  		setCurrentModule( module );
  
  		function createModule() {
  			var parentModule = config.moduleStack.length ?
  				config.moduleStack.slice( -1 )[ 0 ] : null;
  			var moduleName = parentModule !== null ?
  				[ parentModule.name, name ].join( " > " ) : name;
  			var module = {
  				name: moduleName,
  				parentModule: parentModule,
  				tests: []
  			};
  
  			var env = {};
  			if ( parentModule ) {
  				extend( env, parentModule.testEnvironment );
  				delete env.beforeEach;
  				delete env.afterEach;
  			}
  			extend( env, testEnvironment );
  			module.testEnvironment = env;
  
  			config.modules.push( module );
  			return module;
  		}
  
  		function setCurrentModule( module ) {
  			config.currentModule = module;
  		}
  
  	},
  
  	// DEPRECATED: QUnit.asyncTest() will be removed in QUnit 2.0.
  	asyncTest: asyncTest,
  
  	test: test,
  
  	skip: skip,
  
  	only: only,
  
  	// DEPRECATED: The functionality of QUnit.start() will be altered in QUnit 2.0.
  	// In QUnit 2.0, invoking it will ONLY affect the `QUnit.config.autostart` blocking behavior.
  	start: function( count ) {
  		var globalStartAlreadyCalled = globalStartCalled;
  
  		if ( !config.current ) {
  			globalStartCalled = true;
  
  			if ( runStarted ) {
  				throw new Error( "Called start() outside of a test context while already started" );
  			} else if ( globalStartAlreadyCalled || count > 1 ) {
  				throw new Error( "Called start() outside of a test context too many times" );
  			} else if ( config.autostart ) {
  				throw new Error( "Called start() outside of a test context when " +
  					"QUnit.config.autostart was true" );
  			} else if ( !config.pageLoaded ) {
  
  				// The page isn't completely loaded yet, so bail out and let `QUnit.load` handle it
  				config.autostart = true;
  				return;
  			}
  		} else {
  
  			// If a test is running, adjust its semaphore
  			config.current.semaphore -= count || 1;
  
  			// If semaphore is non-numeric, throw error
  			if ( isNaN( config.current.semaphore ) ) {
  				config.current.semaphore = 0;
  
  				QUnit.pushFailure(
  					"Called start() with a non-numeric decrement.",
  					sourceFromStacktrace( 2 )
  				);
  				return;
  			}
  
  			// Don't start until equal number of stop-calls
  			if ( config.current.semaphore > 0 ) {
  				return;
  			}
  
  			// throw an Error if start is called more often than stop
  			if ( config.current.semaphore < 0 ) {
  				config.current.semaphore = 0;
  
  				QUnit.pushFailure(
  					"Called start() while already started (test's semaphore was 0 already)",
  					sourceFromStacktrace( 2 )
  				);
  				return;
  			}
  		}
  
  		resumeProcessing();
  	},
  
  	// DEPRECATED: QUnit.stop() will be removed in QUnit 2.0.
  	stop: function( count ) {
  
  		// If there isn't a test running, don't allow QUnit.stop() to be called
  		if ( !config.current ) {
  			throw new Error( "Called stop() outside of a test context" );
  		}
  
  		// If a test is running, adjust its semaphore
  		config.current.semaphore += count || 1;
  
  		pauseProcessing();
  	},
  
  	config: config,
  
  	is: is,
  
  	objectType: objectType,
  
  	extend: extend,
  
  	load: function() {
  		config.pageLoaded = true;
  
  		// Initialize the configuration options
  		extend( config, {
  			stats: { all: 0, bad: 0 },
  			moduleStats: { all: 0, bad: 0 },
  			started: 0,
  			updateRate: 1000,
  			autostart: true,
  			filter: ""
  		}, true );
  
  		config.blocking = false;
  
  		if ( config.autostart ) {
  			resumeProcessing();
  		}
  	},
  
  	stack: function( offset ) {
  		offset = ( offset || 0 ) + 2;
  		return sourceFromStacktrace( offset );
  	}
  });
  
  registerLoggingCallbacks( QUnit );
  
  function begin() {
  	var i, l,
  		modulesLog = [];
  
  	// If the test run hasn't officially begun yet
  	if ( !config.started ) {
  
  		// Record the time of the test run's beginning
  		config.started = now();
  
  		verifyLoggingCallbacks();
  
  		// Delete the loose unnamed module if unused.
  		if ( config.modules[ 0 ].name === "" && config.modules[ 0 ].tests.length === 0 ) {
  			config.modules.shift();
  		}
  
  		// Avoid unnecessary information by not logging modules' test environments
  		for ( i = 0, l = config.modules.length; i < l; i++ ) {
  			modulesLog.push({
  				name: config.modules[ i ].name,
  				tests: config.modules[ i ].tests
  			});
  		}
  
  		// The test run is officially beginning now
  		runLoggingCallbacks( "begin", {
  			totalTests: Test.count,
  			modules: modulesLog
  		});
  	}
  
  	config.blocking = false;
  	process( true );
  }
  
  function process( last ) {
  	function next() {
  		process( last );
  	}
  	var start = now();
  	config.depth = ( config.depth || 0 ) + 1;
  
  	while ( config.queue.length && !config.blocking ) {
  		if ( !defined.setTimeout || config.updateRate <= 0 ||
  				( ( now() - start ) < config.updateRate ) ) {
  			if ( config.current ) {
  
  				// Reset async tracking for each phase of the Test lifecycle
  				config.current.usedAsync = false;
  			}
  			config.queue.shift()();
  		} else {
  			setTimeout( next, 13 );
  			break;
  		}
  	}
  	config.depth--;
  	if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
  		done();
  	}
  }
  
  function pauseProcessing() {
  	config.blocking = true;
  
  	if ( config.testTimeout && defined.setTimeout ) {
  		clearTimeout( config.timeout );
  		config.timeout = setTimeout(function() {
  			if ( config.current ) {
  				config.current.semaphore = 0;
  				QUnit.pushFailure( "Test timed out", sourceFromStacktrace( 2 ) );
  			} else {
  				throw new Error( "Test timed out" );
  			}
  			resumeProcessing();
  		}, config.testTimeout );
  	}
  }
  
  function resumeProcessing() {
  	runStarted = true;
  
  	// A slight delay to allow this iteration of the event loop to finish (more assertions, etc.)
  	if ( defined.setTimeout ) {
  		setTimeout(function() {
  			if ( config.current && config.current.semaphore > 0 ) {
  				return;
  			}
  			if ( config.timeout ) {
  				clearTimeout( config.timeout );
  			}
  
  			begin();
  		}, 13 );
  	} else {
  		begin();
  	}
  }
  
  function done() {
  	var runtime, passed;
  
  	config.autorun = true;
  
  	// Log the last module results
  	if ( config.previousModule ) {
  		runLoggingCallbacks( "moduleDone", {
  			name: config.previousModule.name,
  			tests: config.previousModule.tests,
  			failed: config.moduleStats.bad,
  			passed: config.moduleStats.all - config.moduleStats.bad,
  			total: config.moduleStats.all,
  			runtime: now() - config.moduleStats.started
  		});
  	}
  	delete config.previousModule;
  
  	runtime = now() - config.started;
  	passed = config.stats.all - config.stats.bad;
  
  	runLoggingCallbacks( "done", {
  		failed: config.stats.bad,
  		passed: passed,
  		total: config.stats.all,
  		runtime: runtime
  	});
  }
  
  function setHook( module, hookName ) {
  	if ( module.testEnvironment === undefined ) {
  		module.testEnvironment = {};
  	}
  
  	return function( callback ) {
  		module.testEnvironment[ hookName ] = callback;
  	};
  }
  