/*
 * nclude.js 0.1 beta - Dynamic javascript library loader
 *
 * Copyright (c) 2008 Anders Mattson (creativedistrict.se)
 * Dual licensed under the MIT and GPL licenses.
 *
 */

/**
 * Base function and namespace for the grab utility
 * @param {Object} nm The name of the library
 * @param {Object} fn The callback to execute once the library is finished.
 */
var nclude = function( path, fn ){
	if ( !( this instanceof arguments.callee ) ) return new nclude( path, fn ); 
	if (path.constructor === Function) {
		if (!nclude.isReady) 
			nclude._ready.push(function(){
				nclude(path);
			});
		else 
			this.auto(path);
		return this;
	}
	this.path = ( path.constructor === String ) ? ( path.indexOf( "," ) > -1 ? path.replace( ' ', '' ).split( ',' ) : [ path ] ) : path;
	this.count = this.path.length;
	if (fn) {
		if(!nclude.isReady) nclude._ready.push(fn);
		else this.to(fn);
	}
	return this;
};

window.nclude = nclude;

(function($){
	
	// Stores already loaded libraries and links
	$._cdn = [];
	$._links = [];
	
	$.prototype.auto = function(fn){
		
		/*
		 * Might do something more here with the function string to ensure that it doesn't scan strings and stuff,
		 * plus there might be some things that can be removed from it to make it 
		 * smaller ("var " and all special signs, "=(){}<>" etc., for instance).
		 */
		var str = fn.toString().replace(' ', '').replace(/\r\n\t/g,'');
		var dep = [], m;
		
		// Find Google dependencies
		if (str.match(/google\./g)) {
			dep.push('google');
			
			if (str.match(/google\.search|G(blog|book|image|local|news|patent|video|web)?Search|GdrawOptions/g)) 
				dep.push('google.search');
			
			if (str.match(/google\.maps|G(Map|Map2|LatLng)/g)) 
				dep.push('google.maps');
			
			if(m = str.match(/google\.(feeds|language|earth|gears|gdata|visualization)/g))
				dep = dep.concat(m);
		}
		
		
		// The YUI library
		if (str.match(/YAHOO\./g)) {
		
			dep.push('yahoo');

			// First, the simple ones
			str.replace(/YAHOO\.widget\.(YUILoader|AutoComplete|Cookie|Get|History|ImageCropper|Profiler(Viewer)?|Resize|Selector|ImageLoader|Layout|Tab|Button)/,function(){
				if ( arguments[ 1 ] ) dep.push( arguments[ 1 ].toLowerCase( ) );
			});
			
			// yahoo.animation
			if (str.match(/YAHOO\.util\.((Color)?Anim(Mgr)?|Bezier|Easing|Motion|Scroll)/g)) 
				dep.push('yahoo.animation');
			
			// yahoo.calendar
			if (str.match(/YAHOO\.widget\.(DateMath|Calendar(2up|_Core|Group|Navigator)?)/g)) 
				dep.push('yahoo.calendar');
			
			// yahoo.charts
			if (str.match(/YAHOO\.widget\.((Bar|Cartesian|Category|Chart|Column|FlashAdapter|Line|Numeric|Pie|Stacked(Bar|Column))?(Axis|Chart|Series)?)/g)) 
				dep.push('yahoo.charts');
			
			// yahoo.colorpicker
			if (str.match(/YAHOO\.(widget|util)\.Color(Picker)?/g)) 
				dep.push('yahoo.colorpicker');
			
			// yahoo.connection
			if (str.match(/YAHOO\.util\.Connect/g)) 
				dep.push('yahoo.connection');
			
			// yahoo.container
			if (str.match(/YAHOO\.(util\.Config|widget\.(ContainerEffect|Module|Overlay(Manager)?|Panel|(Simple)?Dialog|Tooltip))/g)) 
				dep.push('yahoo.container');
			
			// yahoo.datasource
			if (str.match(/YAHOO\.util\.(Date(Locale)?|(Function|Local|ScriptNode|XHR)?DataSource(Base)?|Number)/g)) 
				dep.push('yahoo.datasource');
				
			// yahoo.datatable
			if(str.match(/YAHOO\.(util|widget)\.(Chain|Sort|Column(Set|DD|Resizer)?|Record(Set)?|(Scrolling)?DataTable|(Text(area|box)|Base|Checkbox|Date|Dropdown|Radio)?CellEditor)/g))
				dep.push('yahoo.datatable');
				
			// yahoo.dom
			if(str.match(/YAHOO\.util\.(Point|Dom|Region)/g))
				dep.push('yahoo.dom');
				
			// yahoo.dragdrop
			if(str.match(/YAHOO\.util\.(DD(Proxy|Target|)?|DragDrop(Mgr(\.ElementWrapper)?)?)/g))
				dep.push('yahoo.dragdrop');
				
			// yahoo.editor
			if(str.match(/YAHOO\.widget\.((Simple)?Editor(Info|Window)?|Toolbar(Button(Advanced)?)?)/g))
				dep.push('yahoo.editor');
				
			// yahoo.element
			if(str.match(/YAHOO\.util\.(Element|Attribute(Provider)?)/g))
				dep.push('yahoo.element');
				
			// yahoo.event
			if(str.match(/YAHOO\.util\.((Custom)?Event(Provider)?|KeyListener|Subscriber)/g))
				dep.push('yahoo.event');
				
			// yahoo.logger
			if(str.match(/YAHOO\.widget\.(Log(ger|Msg|Reader|Writer))/g))
				dep.push('yahoo.logger');
				
			// yahoo.menu
			if(str.match(/YAHOO\.widget\.((Context)?Menu((Bar)?(Item)?|Manager)?)/g))
				dep.push('yahoo.menu');
				
			// yahoo.paginator
			if(str.match(/YAHOO\.widget\.Paginator(\.ui\.(CurrentPageReport|(First|Next|Last|Previous)?PageLink(s)?|RowsPerPageDropdown))?/g))
				dep.push('yahoo.paginator');
				
			// yahoo.slider
			if(str.match(/YAHOO\.widget\.(Dual)?Slider(Thumb)?/g))
				dep.push('yahoo.slider');
				
			// yahoo.treeview
			if(str.match(/YAHOO\.widget\.((Data|HTML|Menu|Root|Text)?Node|TreeView|TV(Anim|Fade(In|Out)))/g))
				dep.push('yahoo.treeview');
				
			// yahoo.uploader
			if(str.match(/YAHOO\.widget\.(FlashAdapter|Uploader)/g))
				dep.push('yahoo.uploader');
				
			// yahoo.yuitest
			if(str.match(/YAHOO\.(tool\.Test(Case(\.Wait)?|Logger|Manager|Node|Reporter|Runner|Suite)|util\.((Array|Date|Object)?Assert(ionError)?|ComparisonFailure|Should(Error|Fail)|Unexpected(Error|Value)|UserAction))/g))
				dep.push('yahoo.yuitest');
		}

		// Special handle of the JSON object. Needs more attention, since it not namespaced (collides with Mootools JSON object for instance).
		// Don't know if this collides with anything. If it collides with any other library, one way to handle
		// this would be to determine which libraries are present and then prioritize between them if there's more than one.
		// yahoo.json
		if(str.match(/JSON/g))
			dep.push('yahoo.json');
				
		// Dojo Toolkit
		// Doing this separate first, might find a way to consolidate them later on.
		
		// dojo.*
		if(str.match(/dojo\./g)){
			dep.push('dojo');

			if(str.indexOf('dojo.dnd')>-1) dep.push('dojo.dnd.common');
			if(str.indexOf('dojo.dnd.autoScroll')>-1) dep.push('dojo.dnd.autoscroll');
			
			if(m = str.match(/dojo\.(AdapterRegistry|back|behavior|cldr\.(monetary|supplemental)|colors|cookie|currency|data\.(ItemFileReadStore|ItemFileWriteStore|api\.(Identity|Notification|Read|Request|Write)|util\.(filter|simpleFetch|sorter))|date(\.(locale|stamp))?|DeferredList|fx(\.(easing))?|gears|html|i18n|io(\.iframe|script)|jaxer|NodeList\-(fx|html)|number|OpenAjax|parser|regexp|resources\.\_modules|robot(x)?|rpc\.(JsonpService|JsonService|RpcService)|string|dnd\.(Avatar|Container|Manager|move|Moveable|Mover|Selector|Source|TimedMoveable))/g))
				dep = dep.concat(m);
		}

		// dijit.*
		if(str.match(/dijit\./g)){
			
			// Some things that couldn't be parsed the normal way
			if(str.indexOf('dijit.layout.Tab')>-1) dep.push('dijit.layout.TabContainer');
			if(str.match(/dijit\.((Tooltip)?Dialog(Underlay)?)/g)) dep.push('dijit.Dialog');
			if(str.match(/dijit\.form\.((Combo|DropDown)?Button)/g)) dep.push('dijit.form.Button');
			if(str.match(/dijit\.form\.(CheckBox|RadioButton)/g)) dep.push('dijit.form.CheckBox');
			if(str.match(/dijit\.form\.(Slider|Horizontal(Rule(Labels)?|Slider))/g)) dep.push('dijit.form.Slider');
			if(str.match(/dijit\.form\.((Validation|Mapped|RangeBound)TextBox)/g)) dep.push('dijit.form.ValidationTextBox');
			if(str.match(/dijit\.layout\.(\_LayoutWidget|layoutChildren|marginBox2contentBox)/g)) dep.push('dijit.layout._LayoutWidget');
			if(str.match(/dijit\.layout\.(Accordion(Container|Pane))/g)) dep.push('dijit.layout.AccordionContainer');
			if(str.match(/dijit\.((Checked|Popup)?Menu(Item)?)/g)) dep.push('dijit.Menu');
			
			var m = str.match(/dijit\.(Toolbar\_Calendar|\_Container|\_editor\.(\_Plugin|html|plugins\.(AlwaysShowToolbar|EnterKeyHandling|FontChoice|LinkDialog|TabIndent|TextColor|ToggleDir)|range|RichText|selection)|\_Templated|\_TimePicker|\_tree\.(dndContainer|dndSelector|dndSource|model)|\_Widget|ColorPalette|Declaration|Editor|form\.(_DateTimeTextBox|_FormWidget|_Spinner|CurrencyTextBox|DateTextBox|FilteringSelect|Form|MultiSelect|NumberSpinner|SimpleTextarea|Textarea|TextBox|TimeTextBox|NumberTextBox|ComboBox)|InlineEditBox|layout\.(BorderContainer|ContentPane|LayoutContainer|LinkPane|SplitContainer|StackContainer)|ProgressBar|resources\.\_modules|robot(x)?|TitlePane|Tooltip|Tree)/g);
			if(m && m.length) dep = dep.concat(m);
		}

		// dojox.*
		if(str.match(/dojox\./g)){
			var m;
			// Dividing it in to subprojects for now
			if(m = str.match(/dojox\.av\.[a-zA-z\.]+/g))
				dep = dep.concat(m);

			if(m = str.match(/dojox\.charting\.(Chart(2|3)D|Element|Series|Theme|action2d\.(Base|Highlight|Magnify|MoveSlice|Shake|Tooltip)|(axis|plot)(2|3)d\.(Areas|Bars|Base|Cylinders|Bubble|Clustered(Bars|Columns)|Columns|Default|Grid|Lines|Markers(Only)?|Pie|Scatter|Stacked(Areas|Bars|Columns|Lines)?|common)|scaler\.(common|linear|primitive)|widget\.(Chart2D|Legend|Sparkline))/g))
				dep = dep.concat(m);

			if(m = str.match(/dojox\.(date|form|widget)\.[a-zA-Z]+/g))
				dep = dep.concat(m);

			if(m = str.match(/dojox\.embed\.(Flash|Object|Quicktime)/g))
				dep = dep.concat(m);
			
			// Quickadd some of the base dependencies
			if(m = str.match(/dojox\.(collections|color|cometd|dtl|flash|fx|gfx|html|jsonPath|math|off|presentation|editor\.plugins\.UploadImage)/g))
				dep = dep.concat(m);

			if(m = str.match(/dojox\.collections\.(ArrayList|Dictionary|BinaryTree|Queue|SortedList|Stack)/g))
				dep = dep.concat(m);

			if(m = str.match(/dojox\.color\.(Colorspace|Generator|Palette)?/g))
				dep = dep.concat(m);

			if(m = str.match(/dojox\.cometd\.((callback|long)?PollTransport(FormEncoded|JsonEncoded)?|time(sync|stamp)?|RestChannels)?/g))
				dep = dep.concat(m);				

			if(m = str.match(/dojox\.json\.(query|ref|schema)/g))
				dep = dep.concat(m);

			if(m = str.match(/dojox\.html\.(metrics|styles)/g))
				dep = dep.concat(m);

			if(m = str.match(/dojox\.jsonPath\.query/g))
				dep = dep.concat(m);

			if(m = str.match(/dojox\.io\.(scriptFrame|windowName|xhr(Plugins|MultiPart|WindowNamePlugin)|httpParse|proxy\.zip)/g))
				dep = dep.concat(m);

			if(m = str.match(/dojox\.math\.(curves|matrix)/g))
				dep = dep.concat(m);

			if(m = str.match(/dojox\.off\.(files|sync|ui)/g))
				dep = dep.concat(m);

			if(str.match(/dojox\.editor\.plugins\.[a-zA-Z]+Table/g))
				dep.push('dojox.editor.plugins.TablePlugins');

			if(m = str.match(/dojox\.data/g)){
				
				// Special handle of the dojox.data.XmlItem import and (A)SYNC_MODE
				if(str.match(/dojox\.data\.Xml/g)) dep.push('dojox.data.XmlStore');
				if(str.match(/dojox\.data\.(A)?SYNC_MODE/g)) dep.push('dojox.data.jsonPathStore');
				
				if(m = str.match(/dojox\.data\.(css|dom|restListener|[a-zA-Z]+Store)/g))
					dep = dep.concat(m);
			}

			if(str.match(/dojox\.dtl/g)){
				if(str.match(/dojox\.dtl\.((Attribute|Change)Node|Html(Buffer|Template)|html\.(getTemplate|tokenize))/g))
					dep = dep.push('dojox.dtl.html');

				if(m = str.match(/dojox\.dtl\.((render\.html|utils\.date)|(contrib|filter|tag)\.[a-z]+)/g))
					dep = dep.concat(m);				
			}

			if(str.match(/dojox\.encoding/g)){
				dep.push('dojox.encoding._base');
				if(m = str.match(/dojox\.encoding\.(ascii85|base64|bits|easy64|compression\.(lzw|splay)|crypto\.Blowfish|digests\.MD5)/g))
					dep = dep.concat(m);
			}

			if(str.match(/dojox\.fx/g)){
				if(m = str.match(/dojox\.fx\.(flip|easing|style|Shadow)/g))
					dep = dep.concat(m);

				if(str.match(/dojox\.fx\.s(moothS)?croll/g))
					dep.push('dojox.fx.scroll');

				if(str.match(/dojox\.fx\.ext\-dojo/g))
					dep.push('dojox.fx.ext-dojo.NodeList');
			}
			
			/* Done down to here */
/*			
			if(str.match(/dojox\.gfx/g)){}
			if(str.match(/dojox\.analytics/g)){}
			if(str.match(/dojox\.gfx3d/g)){}
			if(str.match(/dojox\.grid/g)){}
			if(str.match(/dojox\.help/g)){}
			if(str.match(/dojox\.image/g)){}
			if(str.match(/dojox\.lang/g)){}
			if(str.match(/dojox\.layout/g)){}
			if(str.match(/dojox\.regexp/g)){}
			if(str.match(/dojox\.rpc/g)){}
			if(str.match(/dojox\.secure/g)){}
			if(str.match(/dojox\.sketch/g)){}
			if(str.match(/dojox\.sql/g)){}
			if(str.match(/dojox\.storage/g)){}
			if(str.match(/dojox\.string/g)){}
			if(str.match(/dojox\.testing/g)){}
			if(str.match(/dojox\.timing/g)){}
			if(str.match(/dojox\.uuid/g)){}
			if(str.match(/dojox\.validate/g)){}
			if(str.match(/dojox\.wire/g)){}
			if(str.match(/dojox\.xml/g)){}
			if(str.match(/dojox\.xmpp/g)){}
*/
		}
		
		// jQuery.
		// For now, since this is supposed to be sort of a "mashup some libraries" kind of script, and since jQuery is the 
		// only of the $ libs that has a solution for working with others, jQuery is only supported through the 'jQuery' function, 
		// not the $ function.
		if(str.match(/jQuery(\([^\)]*\)|\.noConflict)/))
			dep.push('jquery');

		// jQuery UI (needs a better regexp to match more correctly)
		if(str.match(/jQuery\([^\)]*\)\.(draggable|droppable|sortable|selectable|resizable|accordion|datepicker|dialog|progressbar|slider|tabs|)\(/g))
			dep.push('jquery.ui');
		
		// Ext.
		// Not sure wether or not this should be supported since it's only available through cachefile.net (is it stable?)
		if(str.match(/Ext\./g))
			dep.push('extjs');
		
		// SWFObject.
		if(str.match(/swfobject\.(registerObject|get(ObjectById|QueryParamValue)|(get|has)FlashPlayerVersion|add(Dom)?LoadEvent|(create|embed|remove)SWF|createCSS)/g))
			dep.push('swfobject');
		
		// GChart.
		if(str.match(/GChart/g))
			dep.push('gchart');
		
		// Removing any duplicates
		var _tmp = [], out = [];
		for(var i = 0, l = dep.length; i < l; i++ ){
			if(_tmp[dep[i]]) continue;
			_tmp[dep[i]] = 1;
			out.push(dep[i]);
		}
		
		if( dep.length ) return $( dep.join(','), fn );
		else return fn.call();
	}

	/**
	 * Adds and executes the callback and check/get the script and any links if needed.
	 * @param {Function} fn
	 */
	$.prototype.to = function( fn ) {
		var self = this;
		// Need this to be able to run the function without a callback.
		fn = fn || function(){};
		
		// Check if we're loading multiple paths before executing the callback
		if ( this.path.length > 1 ) {
			for( var i = 0, l = this.path.length; i < l; i++ ) {
				var _path = this.path[ i ];
				$( this.path[ i ], function( ) {
					self.count--;
					if( self.count == 0 ) fn.call( true );
				});
			}
			return this;
		}
		
		// Lots of scope to keep track of. Better use this than creating a new variable outside every new function.
		var nm = this.path[ 0 ];
	
		// Just execute the callback if the library is already loaded.
		if( $._cdn[ nm ] ) {
			fn.call( true );
			return;
		}
	
		var cur;
		
		// Find the first pattern that match
		for( var i = 0; i < $.cdn.length; i++ ) {
			if( nm.match( $.cdn[i].pattern ) ) {
				cur = $.cdn[ i ];
				break;
			}
		}
		
		// If no pattern matched it means that no support for the library was found or the path was incorrect.
		if( !cur ) throw new Error( 'Library ' + nm + ' currently not supported' );
		
		// Check and load dependencies.
		if( cur.require && cur.require.length ) {
			for( var i = 0, l = cur.require.length; i < l; i++ ) {
				if( !$._cdn[ cur.require[ i ] ] ) {
					$( cur.require[ i ], function() {
						$( nm, fn );
					});
					return self;
				}
			}
		}
		
		// Apply the before callback if any.
		if ( cur.before && cur.before.apply( cur, [ nm ] ) === false ) return fn.call( false );
		
		// Load any css that the library needs.
		if( cur.links && cur.links.length ) {
			for( var i = 0, l = cur.links.length; i < l; i++ ) {
				$.link( cur.links[ i ] );
			}
		}
		
		// Libraries and their components can be loaded by url or by a custom function (like the YUI components).
		
		// Check for an url, and create a script tag for it if it exists.
		if ( cur.url ) $.js( nm, cur.url, fn );
		
		// No url was defined, check for a custom function.
		else if ( cur.fn ) cur.fn( nm, fn );
		
		// No url of custom function was defined, just execute the callback and return.
		else fn.call(true);
		
		return this;
	};
	
	/**
	 * Function for extending the list of available libraries.
	 * TODO: More sufficient check for array/object argument.
	 * @param {Object} o
	 */
	$.reg = function( o ){
		(o.constructor === Object) ? $.cdn.push( o ) : $.cdn = $.cdn.concat(o);
		return this;
	};
	
	/**
	 * Adds a link to a css file in the header of the document.
	 * Currently, the callback for the javascript file isn't waiting for the css to be loaded, 
	 * since there is no programmatical dependency on css in the javascript.
	 * 
	 * @param {String} href
	 */
	$.link = function( href ){
		href = $._setUrl(href);
		if( $._links[ href ] ) return;
		var link = document.createElement( 'link' );
		link.type = 'text/css';
		link.href = href;
		link.rel = 'stylesheet';
		document.getElementsByTagName( 'head' )[ 0 ].appendChild( link );
		$._links[ href ] = true;
	
	};
	
	/**
	 * Utility function for adding a script to the DOM.
	 * @param {String} path
	 * @param {String} src
	 * @param {Function} fn
	 */
	$.js = function(path, src, fn){
		if( !$._cdn[ path ] ) {
			src = $._setUrl(src);
			var script = document.createElement( 'script' );
			script.src = src;
			if(script.addEventListener){
				script.addEventListener('load',function(){
					$._cdn[ path ] = true;
//					alert('event');
					fn.call(true);
					script = null;				
				},false);
			}
			else {
				script.onreadystatechange = function(){
					if ( !this.readyState || this.readyState == 'loaded' || this.readyState == 'complete' ) {
						$._cdn[ path ] = true;
						fn.call(true);
						script = null;
					}
				};
			}
			document.getElementsByTagName( 'head' )[ 0 ].appendChild( script );
		}
		else fn.call(true);
	};
	
	/**
	 * Adds a class to the selected element.
	 * @param {String} cls
	 * @param {Element} domnode 
	 */
	$.addClass = function(cls, domnode){
		var domcls = domnode.className;
		if(domcls.indexOf(cls) == -1) domnode.className += (domcls.length ? ' ' : '') + cls;
	};
	
	$._setUrl = function(url){
		url = url.replace(/\{([a-z0-9\.]+)\|([a-z0-9\.]+)\}/gi, function(){return nclude.config(arguments[1], null, arguments[2])});
		return url;
	}
	
	/**
	 * Function for setting some of the already supported libraries configuration. This can also
	 * be used when extending it to support more libraries.
	 * 
	 * @param {Object} prop
	 * @param {String} val
	 * @param {Object} def
	 */
	$.config = function(prop, val, def){
		if(prop.constructor == Object)
			for(var p in prop)
				$._config[p] = prop[ p ];
		else if(val) 
			$._config[ prop ] = val;
		else 
			return $._config[ prop ] || def;
	};
	
	$._ready = [];
	$.isReady = false;
	$._timer = null;
	
	$.ready = function(){
		// quit if this function has already been called
		if ($.isReady) return;
		
		// flag this function so we don't do the same thing twice
		$.isReady = true;
		
		// kill the timer
		if ($._timer) {
			clearInterval($._timer);
			$._timer = null;
		}
/*		
		var m;
		if(m = document.body.innerHTML.match(/<[^>]*dojo[tT]ype\="[a-zA-Z\.]+"[^>]*>/g)){
			var dojotypes = m.join('').match(/dojo[tT]ype\="[a-zA-Z\.]+"/g).join('|').replace(/dojo[tT]ype\="/g,'').replace('"','').split('|');
			dojotypes.push('dojo.parser');
			if(dojotypes.length) $(dojotypes.join(','), function(){
				dojo.parser.parse(document.body);
			});
		}
*/
		
		if($._ready.length)
			for(var i = 0, l = $._ready.length; i < l; i++) 
				$($._ready[i]);
	}
	
	// Internal array holding configurations.
	$._config = [];
	
	// The array of supported libraries, filled with some out of the box support.
	$.cdn = [

		// Google JSAPI
		{ 
			pattern: 	/^google$/i,
			url: 		'http://www.google.com/jsapi',
			before:		function(){
							if($.config('google.apikey')) this.url = this.url + '?key='+$.config('google.apikey');
						}
		}
		
		// Google Chart - an easier to understand js implementation of Google Charts
		,{
			pattern:	/^gchart/i,
			url:		'http://ncludejs.appspot.com/js/nclude.gchart.js'
		}
		
		// Google Gears
		,{
			pattern:	/^google\.gears/i,
			fn:			function( p, fn ){
							if (window.google && google.gears) {
								fn.call(true);
								return;
							}
							var f = null;
							if(typeof GearsFactory!='undefined') f = new GearsFactory();
							else{
								try{
									f = new ActiveXObject('Gears.Factory');
									if(f.getBuildInfo().indexOf('ie_mobile')!=-1) f.privateSetGlobalObject(this);
								}
								catch(e){
									if((typeof navigator.mimeTypes!='undefined') && navigator.mimeTypes["application/x-googlegears"]){
										f=document.createElement("object");
										f.style.display="none";
										f.width=0;
										f.height=0;
										f.type="application/x-googlegears";
										document.documentElement.appendChild(f);
									}
								}
							}
							if(!f) return fn.call(false);
							if(!window.google) google={};
							if(!google.gears) google.gears={factory:f};
							fn.call(true);
						}
		}
		
		// Google search API, maps API etc.
		,{
			pattern: 	/^google\.*/i,
			require: 	[ 'google' ],
			fn: 		function( p, fn ){
							var m = p.split( "." )[ 1 ];
							var v = ( { maps: 2, search: 1, feeds: 1, language: 1, gdata: 1, earth: 1, visualization: 1 } )[ m ];
							google.load( m, v, {
								callback: fn
							});
						}
		}
		
		// jQuery
		,{
			pattern: 	/^jquery$/i,
			url: 		'http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js',
			fn:			function(){
							if($.config('jquery.noconflict',null,true))
								jQuery.noConflict();
						}
		}
		
		// jQuery UI
		,{
			pattern: 	/^jquery\.ui$/i,
			require: 	[ 'jquery' ],
			url: 		'http://ajax.googleapis.com/ajax/libs/jqueryui/1.5.2/jquery-ui.min.js',
			before:		function(){
							if($.config('jqueryui.themeurl'))
								$.link($.config('jqueryui.themeurl'));
							else 
								$.link('http://www.cachefile.net/scripts/jquery/plugins/jquery-ui/1.5/themes/{jqueryui.theme|flora}/{jqueryui.theme|flora}.all.css' );
						}
		}

		// Yahoo YUI
		,{
			pattern: 	/^(yahoo|yui)$/i,
			url: 		'http://yui.yahooapis.com/combo?2.6.0/build/yuiloader/yuiloader-min.js',
			before:		function(){
				$.addClass('yui-skin-'+$.config('yui.skin',null,'sam'), document.body);
			}
		}
		
		// Yahoo YUI components
		,{
			pattern: 	/^(yahoo|yui)\.*/i,
			require: 	[ 'yahoo' ],
			fn: 		function(p, fn){
							(new YAHOO.util.YUILoader({ 
								require: 		[ p.split( "." )[ 1 ] ], 
								loadOptional: 	false, 
								combine: 		false, 
								filter: 		'MIN', 
								allowRollup: 	true, 
								onSuccess: 		fn
							})).insert();			
						}
		}
		
		// Dojo Toolkit (including dijit and dojox)
		,{
			pattern: 	/^dojo$/i,
			url: 		'http://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dojo/dojo.xd.js.uncompressed.js',
			links:		[
							'http://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dojo/resources/dojo.css'
						],
			before: 	function(){
							var djConfig = window.djConfig = { afterOnLoad: true };
						}
		}
		
		// dojo/dijit/dojox modules
		,{
			pattern: 	/^(dojo|dojox|dijit)\.*/i,
			require: 	[ 'dojo' ],
			links:		[
							'http://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dijit/themes/dijit.css'
						],
			before:		function(){
							var theme = $.config('dijit.theme',null,'nihilo');
							$.link('http://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dijit/themes/{dijit.theme|nihilo}/{dijit.theme|nihilo}.css');
							$.addClass(theme, document.body);
							return true;
						},
			fn: 		function(p, fn){
							if( $._cdn[ p ] ) return fn.call();
							dojo.require( p );
							var P = p.split(".");
							if(P[0] == "dojox"){
								if (P[1] == 'grid') {
									$.link('http://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dojox/grid/_grid/Grid.css');
									$.link('http://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dojox/grid/_grid/{dijit.theme|nihilo}Grid.css');
								}
								else if (P[1] == "widget") {
									if(P[2] == 'ColorPicker') $.link('http://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dojox/widget/ColorPicker/ColorPicker.css');
									else $.link('http://ajax.googleapis.com/ajax/libs/dojo/1.2.0/' + P.join('/') + '/' + P[P.length - 1] + '.css');
									
								}
								else if (P[1] == "layout" || P[1] == "image" || P[1] == "form") 
									$.link('http://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dojox/' + P[1] + '/resources/' + P[P.length - 1] + '.css');
							}
							else if( P[0] == 'dojo' && P[1] == 'dnd' ) $.link('http://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dojo/resources/dnd.css');
							dojo.addOnLoad( fn );
							$._cdn[ p ] = true;
						}
		}
		
		// Prototype
		,{
			pattern: 	/^prototype$/i,
			url: 		'http://ajax.googleapis.com/ajax/libs/prototype/1.6.0.3/prototype.js'
		}
		
		// MooTools
		,{
			pattern: 	/^mootools$/i,
			url: 		'http://ajax.googleapis.com/ajax/libs/mootools/1.2.1/mootools-yui-compressed.js'
		}
		
		// Script.aculo.us. Needed to make a special type of load since the Script.aculo.us loader 
		// uses document.write to add its modules which doesn't work when loading it dynamically.
		,{
			pattern: 	/^scriptaculous\./i,
			require:	[ 'prototype' ],
			fn: 		function(p, fn){
							if(!Scriptaculous) var Scriptaculous = window.Scriptaculous = {Version: '1.8.1'};
							$.js(p,
								 'http://ajax.googleapis.com/ajax/libs/scriptaculous/1.8.2/' + p.replace('scriptaculous.','') + '.js',
								 fn);
						}
		}
		
		// The SWFObject script
		,{
			pattern:	/^swfobject$/i,
			url:		'http://ajax.googleapis.com/ajax/libs/swfobject/2.1/swfobject.js'
		}
		
		// Extending the list of available libraries
		,{
			pattern:	/^(extjs|domassistant|excanvas|iecanvas|firebuglite|lightbox|modalbox)$/i,
			internal:	true,
			fn:			function(p, fn){
							$.js('nclude.more',
								 'http://ncludejs.appspot.com/js/nclude.more.js',
								 function(){
								 	for( var i = 0, l = $.cdn.length; i < l; i++ ) {
										if($.cdn[i].internal) $.cdn[i].pattern = /^null$/i;
									}
								 	$(p,fn);
								 });
						}
		}
	];
	
	(function(fn) {
		var u = navigator.userAgent;
		var e = /*@cc_on!@*/false; 
		if(/webkit/i.test(u)){
			setTimeout(function(){
				if(document.readyState == "loaded" || document.readyState == "complete") fn();
				else setTimeout(arguments.callee, 10);
			},10);
		}
		else if ((/mozilla/i.test(u) && !/(compati)/.test(u)) || (/opera/i.test(u)))
			document.addEventListener("DOMContentLoaded", fn, false);
		else if (e) {
			(function(){
				var t = document.createElement('doc:rdy');
				try {
					t.doScroll('left');
					fn();
					t = null;
				} 
				catch (E) {
					setTimeout(arguments.callee, 0);
				}
			})();
		}
		else 
			window.onload = fn;
	})($.ready);	
})(nclude);