/* Extend root objects and add basic global functions */
String.prototype.format = function() {   // Given a template, replaces '%s' with remaining parameters, in order.
	// ex: 'hello, %s, you are %s feet tall!'.format('Frank', 6)
	var params = arguments;
	var i = 0;
	var x = function() { return params[i++]; };
	return this.replace(/(%s)/g, x);
};

if (!window.$) {
	$ = function() {   
		// Given one or more elements or IDs, returns the elements. If multiple are requested,
		// returns them as an array.
		// Ex: $('foo').innerHTML = '<br>Grr'
		// inspired by prototype.js - thank you!
		var ret = [];
		for (var i = 0; i < arguments.length; i++) {
			var e = arguments[i];
			if (typeof(e) == 'string')
				e = document.getElementById(e);
			
			if (arguments.length == 1)
				return e;
			
			ret[ret.length] = e;
		}
		
		return ret;
	};
};

String.prototype.strip = function() {
	return this.replace(/^\s+/, '').replace(/\s+$/, '');
};

String.prototype.endswith = function(pattern) {   // returns true if this ends with pattern's value
	var d = this.length - pattern.length;
	return d >= 0 && this.lastIndexOf(pattern) === d;
};

var byu = {
	stage : "prd",//auto set by maven using pom property
	version : "2.1.0",//auto set by maven using pom property
	isIE : ((document.all && document.attachEvent) ? true : false), // true if we're not using Internet Explorer
	stgLoginUrl : "https://login-stg.byu.edu/login/html/login.fcc",//auto set by maven using pom property
	prdLoginUrl : "https://login.byu.edu/login/html/login.fcc",//auto set by maven using pom property
	stgLogoutUrl : "https://login-stg.byu.edu/login/html/logout.html",//auto set by maven using pom property
	prdLogoutUrl : "https://login.byu.edu/login/html/logout.html",//auto set by maven using pom property
	browser : "",
	
	createElement : function(tagName,params){
		var element = document.createElement(tagName);
		
		if(params) {
			for(var param in params) {
				element[param] = params[param];
			}
		}
		return element;
	},
	
	setInnerText : function(el, text) { // hack to set el.innerText. For isIE, uses innerHTML instead (IE has a mem leak)
		if (!byu.isIE)
			el.innerHTML = text;
		else
			el.innerText = text;
	},
	
	makeBound : function(inst, meth) {   // returns the given method as a function bound to the given instance, so that
		// it could e.g. be used as a callback function and still know its instance
		var __method = meth;
		if (__method.__originalMethod) // don't double-bind methods
			__method = __method.__originalMethod;
		
		var bound = function() { return __method.apply(inst, arguments); };
		bound.__originalMethod = __method;
		return bound;
	},
	
	bindMethods : function(inst) { // from various - prototype, MochiKit, etc. Binds all methods in instance
		for (var prop in inst) {
			var meth = inst[prop];
			if (typeof(meth)  == 'function' && prop != 'initialize')
				inst[prop] = byu.makeBound(inst, meth);
			//inst[prop] = meth.bind(inst); //Bind(meth, inst);
		}
	},
	
	evalJSON : function(string) { // Given a JSON string, returns it as an object or an empty object on failure
		string = string || '{}';
		
		var obj = {};
		try {
			eval('obj=' + string);
		}
		catch(e) {	}
		return obj;
	},
	
	toRealArray : function(fakeArray) { // converts an array like object (like function.arguments) into a real array
		var realArray = [];
		for (var i=0; i < fakeArray.length; i++) {
			realArray.push(fakeArray[i]);
		}
		return realArray;
	},
	
	update : function(dest, src) {   // for each property in src, copy to dest
		for (var prop in src)
			dest[prop] = src[prop];
		return dest;
	},
	
	Class : function(parentClass) {   // Creates a "class" and binds all methods to the instance
		func = function() { byu.bindMethods(this); this.initialize.apply(this, arguments); };
		if (parentClass)
			func.prototype = new parentClass;
		return func;
	},
	
	// Applys func to each element in list
	map : function(list, func){
		for(var i=0; i<list.length; ++i) {
			func(list[i]);
		}
	},
	
	unhideElements : function(){
		try {
			var ByuBarLogin = $("ByuBarLogin");
			var ByuBarLoginForm = byu.util.getImmediateChildrenByTagName(ByuBarLogin, 'FORM');
			ByuBarLoginForm[0].style.display = 'block';
			//document.forms.routeYLoginByuBar.USER.focus();
		}
		catch(error){}
	},
	
	closePageElements : function(evt) {
		if(byu.browser == 'safari' || evt.button == 0)//make sure it was the primary mouse button clicked - safari doesn't capture right click mouse events correctly
		{
			try {
				byu.menu.closeMenu();
			}
			catch(error){}
			try {
				byu.qf.close();
			}
			catch(error){}
		}
	},
	
	browserDetect : function() {
		var nv = window.navigator;
		if(nv.userAgent.indexOf("MSIE 6") != -1){ byu.css.addClass(document.documentElement, "ie ie6"); byu.browser = "ie6";}
		if(nv.userAgent.indexOf("MSIE 7") != -1){ byu.css.addClass(document.documentElement, "ie ie7"); byu.browser = "ie7";}
		if(nv.userAgent.indexOf("Firefox") != -1 && nv.platform.indexOf("Win32") != -1){ byu.css.addClass(document.documentElement, "ff ffwin"); byu.browser = "ff";}
		if(nv.userAgent.indexOf("Firefox") != -1 && nv.platform.indexOf("Mac") != -1){ byu.css.addClass(document.documentElement, "ff ffmac"); byu.browser = "ff";}
		if(nv.userAgent.indexOf("Firefox") != -1 && nv.platform.indexOf("Linux") != -1){ byu.css.addClass(document.documentElement, "ff fflinux"); byu.browser = "ff";}
		if(nv.userAgent.indexOf("Safari") != -1 && nv.platform.indexOf("Mac") != -1){ byu.css.addClass(document.documentElement, "safari safarimac"); byu.browser = "safari";}
		if(nv.userAgent.indexOf("Safari") != -1 && nv.platform.indexOf("Win32") != -1){ byu.css.addClass(document.documentElement, "safari safariwin"); byu.browser = "safari";}
	},
	
	none : function(){}
};

byu.url = {
	siteURL : function(url) { // Returns the URL of the site, e.g. http://www.byu.edu/byutickets/football/team.html --> http://www.byu.edu/
		if(!url) return "";
		
		var domainStart = url.indexOf("://");
		if(domainStart <= 0)//invalid/incomplete url so return ""
			return "";
		
		var domainEnd = url.indexOf("/",domainStart + 3);
		
		if(domainEnd === -1)//url only contained the domain so just return url
			return url + "/";
		
		return url.substring(0,domainEnd+1);
	},
	
	base : function(url) { // Returns the URL for the directory, e.g. http://www.byu.edu/byutickets/football/team.html --> http://www.byu.edu/byutickets/football/
		if(!url) return "";
		
		var domainStart = url.indexOf("://");
		var pathEnd = url.lastIndexOf("/");
		if(pathEnd == domainStart + 2)//no path info
			return url + "/";
		
		return url.substring(0,pathEnd+1);
	},
	
	merge : function(baseUrl, relativePath) {   
		// Creates an absolute URL from baseUrl + relativePath. Ex:
		// http://www.google.com/biff/foo.html, bar.html --> http://www.google.com/biff/bar.html
		// http://www.google.com/biff/foo.html, /bar.html --> http://www.google.com/bar.html
		
		if(!relativePath) return baseUrl; //return baseUrl if no relativePath is given
		
		var domainStart = relativePath.indexOf("://");
		if(domainStart > 0)//already complete url so just return it
			return relativePath;
		
		if(relativePath.charAt(0) == '/'){
			return byu.url.siteURL(baseUrl) + relativePath.substr(1);
		}
		return byu.url.base(baseUrl) + relativePath;
	},
	
	parseParams : function(url) {   //parses url parameters from a querystring and returns them as an object
		var i = url.indexOf('?');
		if(i === -1){
			return {};
		}
		
		var ret = {};
		var params = url.substr(i+1).split('&');
		for(var i=0; i<params.length; i++) {
			var param = params[i].split('=', 2);
			if (param.length == 1)
				ret[param[0]] = true;
			else if (param.length == 2)
				ret[param[0]] = decodeURIComponent(param[1]);
		}
		return ret;
	},
	
	setParams : function(url, params) {   // returns the url (minus old query, if any) + the given params (a dictionary) as a query string
		// strip off old query string
		var i = url.indexOf('?');
		if (i != -1)
			url = url.substr(0, i);
		
		var pairs = [];
		for (var i in (params || {}))
			pairs.push(encodeURIComponent(i) + '=' + encodeURIComponent(params[i]));
		
		if (pairs.length == 0) // the caller is just clearing the URL
			return url;
		return url + '?' + pairs.join('&');
	},
	
	getPageParams : function() {   // returns all page query parameters as a dictionary
		return byu.url.parseParams(window.location.search);
	}
};

byu.css = {
	addClass : function(element, className) {   // adds the given class to the element if not already present
		var classes = byu.css.getClasses(element);
		for (var i=0; i < classes.length; i++)
			if (classes[i] == className)
				return; // already present
		element.className = element.className + ' ' + className;
	},
	
	removeClass : function(element, className) {   // removes the specified class from the element if present
		var classes = byu.css.getClasses(element);
		var keepers = [];
		for (var i=0; i < classes.length; i++) {
			var name = classes[i];
			if (name != className)
				keepers.push(name);
		}
		element.className = keepers.join(' ');
	},
	
	getClasses : function(element) {   // returns the elements style class names as an array
		if (!element) return [];
		if (!element.className)
			return [];
		return element.className.split(' ');
	}
};

// Event stuff - thank you prototype.js
byu.event = {
	_listenerFuncs: [],
	
	observe : function(obj, name, cb) {
		var obj = $(obj);
		var listName = '_' + name.toLowerCase() +'Listeners';
		if (obj[listName] == null) {
			obj[listName] = [];
			var listeners = obj[listName];
			var func = function() {
				for (var i=0; i<listeners.length; i++)
					try {
						listeners[i].apply(this, arguments);
					}
					catch (e) {}
			};
			
			if (obj.addEventListener)
				obj.addEventListener(name, func, false);
			else if (obj.attachEvent)
				obj.attachEvent('on'+name, func);
			
			byu.event._listenerFuncs.push([obj, name, func]);
		}
		
		// See if this cb has already been registered
		var handlers = obj[listName];
		for (var i=0; i < handlers.length; i++)
			if (handlers[i] == cb)
				return;
		handlers.push(cb);
	},
	
	stopObserving : function (obj, name, cb) {
		var obj = $(obj);
		var listName = '_%sListeners'.format(name.toLowerCase());
		var listeners = obj[listName];
		if (listeners == null)
			return;
		
		for (var i=0; i < listeners.length; i++) {
			if (listeners[i] == cb) {
				listeners.splice(i, 1);
				if (listeners.length == 0) {   // no more listeners, so completely clear it out so we get no more events
					// (this is especially important w/ e.g. mouse move events!)
					
					// locate the function we originally used for registration of all our handlers
					var func = null;
					var funcs = byu.event._listenerFuncs;
					for (var j=0; j < funcs.length; j++) {
						var entry = funcs[j];
						if (entry[0] == obj && entry[1] == name) {
							func = entry[2];
							funcs.splice(j, 1); // remove it
							break;
						}
					}
					
					if (func == null)
						logError('Could not find all_listener to remove');
					else {
						if (obj.removeEventListener)
							obj.removeEventListener(name, func, false);
						else
							obj.detachEvent('on'+name, func);
					}
					
					obj[listName] = null; // completely clear it out
				}
				break;
			}
		}
	},
	
	removeAllObservers : function() {
		for (var i=0; i< byu.event._listenerFuncs.length; i++) {
			var entry = byu.event._listenerFuncs[i];
			var obj = entry[0];
			var name = entry[1];
			obj['_%sListeners'.format(name.toLowerCase())] = null;
			var func = entry[2];
			entry[0] = null;
			if (obj.removeEventListener)
				obj.removeEventListener(name, func, false);
			else if (obj.detachEvent)
				obj.detachEvent('on'+name, func);
			byu.event._listenerFuncs[i] = null;
		}
	},
	
	fireEvent : function(obj, name) {
		for(var i=0; i<byu.event._listenerFuncs.length; ++i) {
			var entry = byu.event._listenerFuncs[i];
			if(obj == entry[0] && name == entry[1]) {
				entry[2]();
			}
		}
	}
};
// prevent memory leaks in IE - without this circular references exist
byu.event.observe(window, 'unload', byu.event.RemoveAllObservers);

/***********************************************************************
 * Common utility functions
 ***********************************************************************/
byu.util = {
	currentID : 0,
	
	getTextContent : function(element) {
		for(var i=0;i<element.childNodes.length; ++i) {
			if(element.childNodes[i].nodeType === 3)//text node
			{
				return element.childNodes[i].nodeValue;
			}
		}
		return "";
	},
	
	getbaseHREF : function() {//get's base path of stylesheets to be used for image swapping
		if(document.styleSheets.length > 0) {
			var cssUrl = document.styleSheets[0].href;
			return cssUrl.substring(0,cssUrl.indexOf("<?= $pathToRoot; ?>collageTemplates2/templates/"));
		}
		return "";
	},
	
	// getElementsByTagName returns all descendant nodes,
	// but this method returns only those nodes that are immediate children.
	getImmediateChildrenByTagName : function(element, tagName) {
		if( !element ) return []; // quit without error if null is sent in.
		var list = element.getElementsByTagName(tagName);
		// Keep elements that are immediate children of supplied element.
		var finalList = [];
		var finalIdx = 0;
		for( var i = 0; i < list.length; i++ )
			if( list[i].parentNode == element )
				finalList[finalIdx++] = list[i];
		return finalList;
	},
	
	getElementsByClassName : function(className, container, tagName) {
		var outArray = [];
		var all = container.getElementsByTagName(tagName ? tagName : '*');
		for(var i = 0; i < all.length; i++) {
			var classNames = byu.css.getClasses(all[i]);
			for(var j=0; j<classNames.length; ++j)
			{
				if(className == classNames[j])
				{
					outArray[outArray.length] = all[i];
					break;
				}
			}
		}
		return outArray;
	},
	
	// function useful because Safari gets confused when there is more than one element with the same ID 
	// even if only one of the elements is currently being displayed
	getChildElementById : function(parent, id) {
		for(var i=0; i<parent.childNodes.length; ++i) {
			if(parent.childNodes[i].id == id) {
				return parent.childNodes[i];
			}
		}
	},
	
	IsDefined : function(variable) {
		try { var __testIsDefined = eval(variable);} catch(e){}
		if(__testIsDefined != undefined) return true;
		return false;
	},
	
	checkEnter : function(e) {
		if(!byu.isIE) {
			if(e.which == 13) {
				return true;
			}
		}
		
		if(byu.isIE) {
			if(event.keyCode == 13) {
				return true;
			}
		}
		return false;
	},
	
	getUniquePageID : function() {
		return ++byu.util.currentID;
	}
};

byu.auth = {
	clearCookies : function() {
		var expDate = new Date("01/01/1980").toGMTString();
		document.cookie = 'FORMCRED=0;domain=.byu.edu;path=/;expires='+expDate;
		document.cookie = 'SMTRYNO=0;domain=.byu.edu;path=/;expires='+expDate;
		document.cookie = 'SECURE_COOKIE=anakincookieookie; domain=.byu.edu; path=/; expires='+expDate;
		document.cookie = 'usr_byu_edu=anakincookieookie; domain=.byu.edu; path=/; expires='+expDate;
		document.cookie = 'role_byu_edu=anakincookieookie; domain=.byu.edu; path=/; expires='+expDate;
		document.cookie = 'byu_ry_po_session=anakincookieookie; domain=.byu.edu; path=/; expires='+expDate;
		document.cookie = 'SmSESSION=anakincookieookie; domain=.byu.edu; path=/; expires='+expDate;
		document.cookie = 'SMIDENTITY=anakincookieookie; domain=.byu.edu; path=/; expires='+expDate;
		document.cookie = 'SMSESSION=anakincookieookie; domain=.byu.edu; path=/; expires='+expDate;
		document.cookie = 'https%3a%2f%2fhrms.byu.edu%2fpsp%2fhrprd2%2femployee%2fhrms%2frefresh=0;domain=.byu.edu;path=/;expires='+expDate;
		document.cookie = 'PS_TOKENEXPIRE=0;domain=.byu.edu;path=/;expires='+expDate;
		document.cookie = 'PS_TOKEN=0;domain=.byu.edu;path=/;expires='+expDate;
		document.cookie = 'PS_LOGINLIST=0;domain=.byu.edu;path=/;expires='+expDate;
		document.cookie = 'ExpirePage=0;domain=.byu.edu;path=/;expires='+expDate;
		document.cookie = 'SignOnDefault=0;domain=.byu.edu;path=/;expires='+expDate;
		document.cookie = 'HPTabName=0;domain=.byu.edu;path=/;expires='+expDate;
		document.cookie = 'queens-byu-edu-9080-PORTAL-PSJSESSIONID=0;domain=hrms.byu.edu;path=/;expires='+expDate;
		document.cookie = 'dauphin-byu-edu-9080-PORTAL-PSJSESSIONID=0;domain=hrms.byu.edu;path=/;expires='+expDate;
	},
	
	doRYLogin : function() {
		byu.auth.clearCookies();
		if(byu.stage === 'stg')
		{
			window.location = byu.stgLoginUrl;
		}
		else//production
		{
			window.location = byu.prdLoginUrl;
		}
		return true;
	},
	
	doRYLogout : function() {
		byu.auth.clearCookies();
		var logoutString;
		if(byu.stage === 'stg')
		{
			logoutString = byu.stgLogoutUrl;
		}
		else//production
		{
			logoutString = byu.prdLogoutUrl;
		}
		if(byu.util.IsDefined("byuConfig") && byuConfig.targetLogoutURL) {
			logoutString += "?" + byuConfig.targetLogoutURL;
		}
		window.location = logoutString;
	}
};

byu.cookie = {
	setCookie : function(cookieID, cValue, path, expires) {
		//path and expires are optional params.  If expires is null then cookie will expire with the session.
		var expDate = expires || null;
		var cPath = path || null;
		var NameOfCookie = cookieID;
		var cookieString = NameOfCookie + "=" + escape(cValue);
		if(cPath){
			cookieString += ";path=" + cPath;
		}
		if(expDate){
			cookieString += ";expires=" + expDate;
		}
		document.cookie = cookieString;
	},
	
	unsetCookie : function(cookieID) {
		byu.cookie.setCookie(cookieID, null);
	},
	
	getCookie : function(cookieID) {
		var dc = document.cookie, prefix = cookieID + "=", begin = dc.indexOf("; " + prefix);
		if (begin == -1) { 
			begin = dc.indexOf(prefix); 
			if (begin != 0) 
				return null; 
		}
		else 
			begin += 2;
		var end = document.cookie.indexOf(";", begin);
		if (end == -1) 
			end = dc.length;
		return unescape(dc.substring(begin + prefix.length, end));
	}
};

byu.effects = {
	/* 
	 obj - can be the actual object or a string containing the object's id 
	 milliseconds - number of milliseconds the fade should complete in
	 inORout - pass in string 'in' or 'out' depending on if you want the object to fade in or out (defaults to 'out')
	 callBack - callBack function to call when the fade is done
	*/
	fade : function(obj, milliseconds, inORout, callBack) {
		var localObj = $(obj);
		var localCallBack = callBack;
		var timeInterval = 50;
		var increment = 1 / (milliseconds / timeInterval);
		var stopCriteria;
		var inout = inORout || 'out';//default to out
		
		if(!localObj.isFading)//don't let an object fade that is already fading
		{
			localObj.isFading = true;
			var incrementalFade = function() {
				if(stopCriteria(byu.effects.getOpacity(localObj)))
				{
					if(localCallBack)
					{
						setTimeout(localCallBack,1);
					}
					localObj.isFading = false;
					return;
				}
				byu.effects.setOpacity(localObj, byu.effects.getOpacity(localObj) + increment);
				setTimeout(incrementalFade,timeInterval);
			};

			if(inout == 'in')//fade it in
			{
				byu.effects.setOpacity(localObj, 0);//start opacity as completly transparent
				stopCriteria = function(opacity){
					if(opacity >= 1) {
						return true;
					}
					return false;
				};
				incrementalFade();
			}
			else//fade it out
			{
				byu.effects.setOpacity(localObj, 1);//start opacity as completly opaque
				increment = increment * -1;
				stopCriteria = function(opacity){
					if(opacity <= 0) {
						return true;
					}
					return false;
				};
				incrementalFade();
			}
		}
	},
	
	getOpacity : function(obj) {
		var tempOpacity;
		if(byu.isIE) {
			if(!obj.filters[0]) {
				obj.style.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=100)";
			}
			tempOpacity = obj.filters[0].opacity;
			tempOpacity = parseFloat(tempOpacity) / 100;
		}
		else {
			tempOpacity = obj.style.opacity || 1;
		}
		
		tempOpacity = parseFloat(tempOpacity);
		return tempOpacity;
	},
	
	setOpacity : function(obj, opacityLevel) {
		if(byu.isIE) {
			if(!obj.filters[0]) {
				obj.style.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=%s)".format(opacityLevel * 100);
			}
			else {
				obj.filters[0].opacity = opacityLevel * 100;
			}
		}
		else {
			obj.style.opacity = opacityLevel;
		}
	}
};

byu.ajax = {
	xDomainRequests : {},
	
	//allows only url params to be passed
	makeXDomainRequest : function(fullUrl, callback) {
		var requestID = byu.util.getUniquePageID();
		
		//add callback to url
		if(fullUrl.indexOf("?") == -1)//no ?
		{
			fullUrl += "?";
		}
		fullUrl += "&callback=byu.ajax.xDomainCallback&requestID=" + requestID;
		
		var reqObj = new XDomainRequest(fullUrl, requestID);
		reqObj.makeCall();
		
		byu.ajax.xDomainRequests[requestID] = {"fullUrl":fullUrl, "callback":callback, "reqObj":reqObj};
	},
	
	/* Format of resp from server
		byu.ajax.xDomainCallback({ //this function name is passed as url param to server labeled "callback"
						"requestID" : requestID, //pass through the requestID that was sent to server
						"resp" : put your response stuff here can be a string, JSON object or any valid javascript
					});
	 */
	xDomainCallback : function(resp) {
		var request = byu.ajax.xDomainRequests[resp.requestID];
		
		delete byu.ajax.xDomainRequests[resp.requestID];
		
		request.reqObj.cleanUpCall();
		var cb = eval(request.callback);
		cb(resp.resp);
	}
};

/* Class for actually doing the cross domain calls */
function XDomainRequest(fullUrl, reqID) {
	this.fullUrl = fullUrl;
	this.noCacheIE = '&noCacheIE=' + (new Date()).getTime();
	this.headElement = document.getElementsByTagName("head").item(0);
	this.scriptId = 'XDomainId' + reqID;
};
XDomainRequest.prototype.makeCall = function () {
	this.scriptObj = document.createElement("script");
	
	this.scriptObj.setAttribute("type", "text/javascript");
	this.scriptObj.setAttribute("src", this.fullUrl + this.noCacheIE);
	this.scriptObj.setAttribute("id", this.scriptId);
	this.headElement.appendChild(this.scriptObj);
};
XDomainRequest.prototype.cleanUpCall = function () {
	this.scriptObj.parentNode.removeChild(this.scriptObj);
};

byu._findLibbase = function() {   // Returns the base URL to use when loading JS (bases it off alllevels.js)
	var tags = document.getElementsByTagName('script');
	var libURLs = [];
	for (var i=0; i < tags.length; i++) {
		var tag = tags[i];
		var src = tag.src;
		if (!src || !src.endswith('alllevels.js'))
			continue;
		
		return byu.url.merge(null, src.substring(0, src.lastIndexOf('alllevels.js')));
	}
	return byu.url.merge(null, '');
};

byu._allLibs = {};

byu.loadLibrary = function(src){
	// Loads another Javascript library. 'src' can be a full URL or can be treated as relative to alllevels.js.
	// An extension is added as needed.
	// You have no guarantee that the library will be loaded before the page is fully loaded, so if you need
	// to do setup that uses functions in the library to load, use byu.event.observe on window.onload.
	src = byu.url.merge(byu._libbase, src);
	if (!src.endswith('.js'))
		src = src + '.js';
	if (byu._allLibs[src])
		return; // already loaded
	byu._allLibs[src] = true;
	
	document.write('<sc' + 'ript type="text/javascript" src="' + src + '">' + '<' + '/scri' + 'pt>');
};

byu.loadAllLibraries = function(){   // Called when page loads - loads any scripts listed in 'import' attribute of alllevels.js script tag
	var tags = document.getElementsByTagName('script');
	var libURLs = [];
	for(var i=0; i<tags.length; i++) {
		var tag = tags[i];
		var imports = tag.getAttribute('import');
		if (!imports)
			continue;
		imports = imports.split(' ');
		for(var j=0; j<imports.length; j++) {
			var name = imports[j].strip();
			if (name)
				libURLs.push(name);
		}
	}
	
	for (var i=0; i<libURLs.length; i++)
		byu.loadLibrary(libURLs[i]);
};

byu._libbase = byu._findLibbase(); // base URL to alllevels.js

/* Page loading calls */
byu.loadAllLibraries();
if(window.onload) byu.event.observe(window, 'load', window.onload);//capture any hardcoded window onload events
byu.event.observe(document, 'click', byu.closePageElements);
byu.event.observe(window, 'load', byu.browserDetect);