new function () {
	
	var UNKNOWN_PAGE_NAME = "UnknownCBPageName";

	var head = document.getElementsByTagName('head')[0];
	if(head.CB_Bootloader != null){
		return;	
	}
	var CB_Bootloader = new Object();
	//add object to contain global functions
	head.CB_Bootloader = CB_Bootloader;
	var getUrlParam = function( name, queryString ) {
		  name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
		  var regexS = "&?"+name+"=([^&#]*)";
		  var regex = new RegExp( regexS );
		  var results = regex.exec(queryString);
		  if( results == null )
		    return null;
		  else
		    return results[1];
	};

	var implReqs = new Object();
	var checks = [];
	
	var btScriptUrl = null;
	var btScriptUri = null;
	var btScriptQuery = "";
	var scripts = document.getElementsByTagName("script");
	for (var i = 0; i < scripts.length; i++) {
		if (scripts[i].src != null) {
			if (scripts[i].src.indexOf("CBBootLoader.js") > 0) {
				btScriptUrl = scripts[i].src;
				btScriptUri = scripts[i].src.substring(0, scripts[i].src.indexOf("CBBootLoader.js") - 1);
				btScriptQuery = scripts[i].src.substring(scripts[i].src.indexOf("?"));
			}
		}
	}

	var accountName = getUrlParam("account", btScriptQuery);
	if (accountName == null) {
		throw new Error("Must specify account");
	}
	var projectName = getUrlParam("project", btScriptQuery);
	if (projectName == null) {
		throw new Error("Must specify project");
	}
	var pageName = getUrlParam("page", btScriptQuery);
	if (pageName == null) {
		pageName = UNKNOWN_PAGE_NAME;
	}
	var configName = getUrlParam("config", btScriptQuery);
	if (configName == null) {
		configName = "default";
	}
	var waitForLoad = getUrlParam("waitForLoad", btScriptQuery);
	if (waitForLoad == null) {
		waitForLoad = true;
	}
	
	var getAccount = function() {
		//return the project url based on account and project
		return accountName;  
	};
	var getProject = function() {
		//return the project url based on account and project
		return projectName; 
	};
	var getPage = function() {
		//return the project url based on account and project
		return pageName; 
	};
	var getProjectUri = function() {
		//return the project url based on account and project
		return btScriptUri.substring(0, btScriptUri.lastIndexOf("/") + 1) + 
		"sites/" + accountName + "/" + projectName + "/"; 
	};
	
	head.CB_Bootloader.getAccount = getAccount;
	head.CB_Bootloader.getProject = getProject;
	head.CB_Bootloader.getPage = getPage;
	head.CB_Bootloader.getProjectUri = getProjectUri;
	
	//add a script to the page
	head.CB_Bootloader.addImplementation = function(url, className, evalCheck) {
		if (evalCheck != null) {
			checks.push(evalCheck);
		}
		if (url == null) {
			throw new Error("url can't be null");
		}
		if (className != null) {
			if (implReqs[className] == null) {
				implReqs[className] = {};
			} else {
				//only add one implementation per class
				return;
			}
		}
		
		var scripts = document.getElementsByTagName("script");
		for (var i = 0; i < scripts.length; i++) {
			if (scripts[i].src == url) {
				//skip readd
				return;
			}
		}
		
		var newScript = document.createElement("script");
		newScript.src = url;
		newScript.type = "text/javascript";
		head.appendChild(newScript);
	};
	
	var impls = new Object();
	
	head.CB_Bootloader.registerImplementation = function(implName, func) {
		if (implName == null) {
			throw new Error("Can't specify null className");
		}
		if (func == null || typeof func != "function") {
			throw new Error("Must specify function (i.e. class) that you are registering");
		}
		if (impls[implName] == null) {
			impls[implName] = func;
		} else {
			throw new Error("Can't register multiple definitions for same implementation");
		}
	};
	
	var references = new Object();
	var waitForDefinitions = ["codebaby_Config", "codebaby_EntryPoint"];
	var configs = new Object();
	
	head.CB_Bootloader.defineInstance = function(/* string */ reference, 
			/* string */ implName, /* Object */ payload, /*number */ priority, 
			/* 0..1 */ abPercent) {
		if (implName == null) {
			throw new Error("must specify implementation name to create");
		}
		if (reference == null) {
			throw new Error("must specify reference name to gain access to this instance");
		}
		if (payload == null) {
			payload = {};
		}
		if (priority == null) {
			priority = 0;
		}
		//abPercent must be 0..1
		if (abPercent == null || abPercent < 0 || abPercent > 1) {
			abPercent = 1;
		}
		var instanceConfig = {impl: implName, payload: payload, priority: priority, ab: abPercent};
		if (references[reference] == null) {
			references[reference] = [];
		}

		references[reference].unshift(instanceConfig);
		
		//put them in order from highest priority to lowest;
		for (var i = 0; i < references[reference].length - 1; i++) {
			if (references[reference][i].priority < references[reference][i + 1].priority) {
				//swap them so lower priorities go to the end of the array
				var temp = references[reference][i];
				references[reference][i] = references[reference][i + 1];
				references[reference][i+1] = temp;
			}
		}
	};

	var config = null;
	var objectCache = new Object();
	
	head.CB_Bootloader.createInstance = function(reference) {
		
		if (references[reference] == null) {
			throw new Error("reference is not defined");
		}
		//keep using the same objects over and over
		if (objectCache[reference] != null) {
			return objectCache[reference];
		}
		//until config is loaded use really low number
		var userAB  = 0.00001;
		if (config != null) {
			userAB = config.getABNumber();
		}
		var currentTotal = 0;
		for (var i = 0; i < references[reference].length; i++) {
			currentTotal += references[reference][i].ab;
			if (userAB < currentTotal) {
				for (var foo in references[reference][i].payload) {
					//if any payload objects hold references, create them first
					if (references[reference][i].payload[foo].reference != null) {
						references[reference][i].payload[foo] = head.CB_Bootloader.createInstance(references[reference][i].payload[foo].reference);
					}
				}
				objectCache[reference] = new impls[references[reference][i].impl](references[reference][i].payload);
				return objectCache[reference];
			}
		}
	};
	
	//get config by account and project
	//config should have AB split and priority for classes?
	var checkReady = function () {
		for (var i = 0; i < checks.length; i++) {
			try {
				if (eval(checks[i]) !== true) {
					setTimeout(checkReady, 25);
					return false;
				}
			} catch (e) {
				//can't catch exception either
				setTimeout(checkReady, 25);
				return false;
			}
		}

		for (var foo in implReqs) {
			if (impls[foo] == null) {
				setTimeout(checkReady, 25);
				return false;
			}
		}

		for (var i = 0; i < waitForDefinitions.length; i++) {
			if (references[waitForDefinitions[i]] == null) {
				throw new Error("must define reference " + waitForDefinitions[i]);
			}
		}

		//if we're ready, create a what is needed by bootloader and execute the EntryPoint
		config = head.CB_Bootloader.createInstance("codebaby_Config");
		if (config.getLive()) {
			head.CB_Bootloader.createInstance("codebaby_EntryPoint");
		}
		return true;
	};
	
	var loadEntry = function() { 
		//add config js file here; it will provide dependencies for everything else
		head.CB_Bootloader.addImplementation(head.CB_Bootloader.getProjectUri() + configName + ".js", 
		"codebaby.EntryPoint");
		checkReady();
		};
	//call after EntryPoint and anything else requested is loaded
	if (waitForLoad) {
	    if (window.addEventListener) {
	    	window.addEventListener("load", loadEntry, false);
	    } else {
	    	window.attachEvent('onload', loadEntry);
	    }
	} else {
		loadEntry();
	}
	
	//added for test purposes
	head.CBtest_isReady = function() {
		return checkReady();
	};
}();