/**
 * GSI Global API Library
 * Requires prototype.js
 * @author bradleyc
 * @version 0.1a
 */
//________________________________________________________________
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
//	GSI Global

/**
 * GSI NameSpace
 * @constructor
 */
	var GSI = function() {};

/**
 * Initialize the Global Library
 * @private
 */
	GSI.initialize = function()
	{	
	//	Perform window onload methods
		Event.observe( window, "load", GSI.onLoad.bind(this) );
	}

/**
 * Handle the onload event
 * Called from GSI.initialize.
 * @param {Object} evt	The window Event object
 * @private
 */
	GSI.onLoad = function( evt )
	{
		GSI.Browser.initialize();
		GSI.Application.loadBuffer();	
		GSI.StatusMessage.setVisibility( false );
		Element.stopObserving( window, "load", GSI.onLoad )
	}

	
//________________________________________________________________
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
//	Namespaces

/**
 * @constructor
 */
	GSI.NameSpace = function() {};

/**
 * The common directory for classes
 * @type String
 */
	GSI.NameSpace._classPath = "/include/";
	
/**
 * Require a namespace for the application.
 * Pass in an array of namespaces or script urls,
 * all urls must contain a backslash.
 * for local urls, use "./scriptname.js".
 * All other namespaces must be placed into the folder
 * denoted by GSI.NameSpace._classPath (default = "/common/")
 * -- Can be set via setClassPath(); 
 * @param {Array} nsArray	Array of namespaces required
 * @param {Function} callback when complete
 */
	GSI.NameSpace.require = function( nsArray, callback )
	{
		var scriptBuffer = new GSI.Scripts.Buffer();

		for( var i=0,len=nsArray.length;i<len;i++ ) {

		//	Get the namespace
			var ns = nsArray[i];
			
		//	Check to see if it exists - skip this iteration
			if( this.exists(ns) ) continue;
			
		//	Load the script 
			if( ns.indexOf("/") != -1 ){
				scriptBuffer.add( ns );
			} else {
				scriptBuffer.add( this._classPath + ns + ".js" );
			}
		}
		
		scriptBuffer.load( callback );
	}

/**
 * Set the Namespace include classpath
 * @param {Object} path	The root folder with trailing backslash 
 * 											to look for any classes being loaded
 */
	GSI.NameSpace.setClassPath = function( path )
	{
		this._classPath = path;
	}
	
/**
 * Create a namespace
 * @param {String} 	namespace	Namespace to create in dotted form, ie: GSI.Class
 * @return A reference to the new namespace object
 * @type Object
 */
	GSI.NameSpace.create = function( namespace )
	{
	//	Get an array from the namespace by splitting on "."
		var nsArray = namespace.split(".");
		var o = window;
		var ns = "";
		
	//	Create each tier of the namespace in order
		for( var i=0,len=nsArray.length; i<len; i++ )
		{
		//	Get the namespace "part" from the array
			var n = nsArray[i];	
			ns += ( i > 0 ) ? "." + n : n;
			
		//	If we cannot find the NS object, create it
			if( o[n] === undefined ) o[n] = { _nameSpace: ns };
			
			//	Set our object reference to the newly created object	
			o = o[n];	
		}
		
		return o;
	}

/**
 * Check for the existence of a namespace within the DOM
 * @param {String} namespace	The dotted namespace to check for
 * @param {Boolean}	[ref]	return a reference to the namespace
 * @return	{Boolean,Object}
 */
	GSI.NameSpace.exists = function( namespace, ref )
	{
		var nsArray = namespace.split(".");
		var parentObj = window;
		for( var i=0,len=nsArray.length;i<len;i++ )
		{
			var n = nsArray[i];
			if( parentObj[n] === undefined ) return ref ? undefined : false;
			parentObj = parentObj[n];
		}
		return ref ? parentObj : true;
	}
	
//________________________________________________________________
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
//	Classes

	GSI.NameSpace.create("GSI.Class");
	
/**
 * Create a property getter/setter on a class
 * 
 * @param {Object} defaultValue
 * The value to assign to the internal property value upon creation.
 * 
 * @param {Object} get
 * Boolean value sets the enabled state of the get property.
 * A value that is of type 'function' specifies a callback method to use for 
 * parsing the property value before returning the "get" value.
 * For callbacks, the property value is passed as the first and only argument.
 * 
 * @param {Object} set
 * Boolean value sets the enabled state of the set property. False means "read-only"
 * A value that is of type 'function' specifies a callback method to use for
 * parsing the property or newly assigned values. Return value of this callback will
 * set the property value.
 * For callbacks, the arguments are passed as $property, $newValue
 * 
 * @return {Function}
 * The function to use as a getter/setter for class properties.
 */
	GSI.Class.property = function( defaultValue, get, set )
	{
		var $property = ( defaultValue === undefined || defaultValue === null ) ? undefined : defaultValue;
	
		return function()
		{
		//	Check to see if we're doing a "get" or "set"
			var doSet = arguments.length !== 0 && set !== false;
			var doGet = get !== false;
			
		//	Check to see if we have methods to call for set/get
		//	otherwise we'll use default method
			var useSetFunc = typeof( set ) == 'function';
			var useGetFunc= typeof( get ) == 'function';
				
		//	Set the value using a custom method or simply setting the prop to value of arg
			if( doSet ) {
				$property = useSetFunc ? set( $property, arguments[0] ) : arguments[0];
				return $property;
			}
				
		//	Return the value using a custom method or simply return $property
			if ( doGet ) {
				return useGetFunc ? get( $property ) : $property;
			}
		};
	};

//________________________________________________________________
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
//	Utility functions

/**
 * Create an Element (advanced)
 * @param {String} 	tag							the tagname to create
 * @param {String} 	[elId]					the ID of the element
 * @param {String} 	[cssClass]			the CSS class to assign
 * @param {String} 	[inner]					the innerHTML value to assign
 * @param {Element} [parentEl]			the parent of the element
 * @param {Array} 	[childrenArr]		array of children to append to the element
 * @param {Object}	[props]					a property object to apply to the element
 * @param {Function} [beforeAdd]		a method to call on the element before adding to DOM
 * @return A reference to the element
 * @type Element
 */
	GSI.createElement = function( tag, elId, cssClass, inner, parentEl, childrenArr, props, beforeAdd )
	{
		if( tag === undefined ) return;
		if( $(elId) ) {
			el = $(elId);
		}
		else 
		{ 
			try 
			{
				el = document.createElement(tag);
		
		//	Set properties initially to avoid setAttribute issues with IE and type/name
				if( props !== undefined && props !== false )
				{
					for( var i=0; i<props.length; i+=2 )
					{
						el.setAttribute( props[i], props[i+1] );
					}
				}
			}
		//	Screw you IE!!! You dirty sonofabitch.
			catch(e)
			{
				var attributes = " ";
				for( var i=0; i<props.length; i+=2 )
				{
					attributes += ( props[i] + '="' + props[i+1] + '" '); 
				}
				el = document.createElement( '<' + tag + attributes + ' />' );
			}
		}
		
		if( elId !== undefined && elId !== false ) el.id = elId;
		if( cssClass !== undefined && cssClass !== false ) el.className = cssClass;
		if( inner !== undefined && inner !== false ) el.innerHTML = inner;
		if( parentEl !== undefined && parentEl !== false ) parentEl.appendChild( el );
		if( childrenArr !== undefined && childrenArr !== false )
		{
			for( var i=0,len=childrenArr.length; i<len; i++ )
			{
				el.appendChild( childrenArr[i] );
			}
		}
		
		return $(el);
	}
	GSI.$e = GSI.createElement;
	
/**
 * Adds an unique identifier (id) property if one doesn't exist
 * @param {Element} el			An HTML element to fix
 * @param {String} pre			A string prefix for the id
 * @return the element passed in (now has "id" attribute")
 * @type Element
 */
	GSI.fixElementId = function( el, pre  )
	{
		if( el.id === undefined || el.id.length == 0 )
		{
			el.id = GSI.uId( pre );
		}	
		return el;
	}
	
/**
 * Create an unique identifier
 * @param {String} pre 	Prefix for the string
 * @return A new unique identifier
 * @type String
 */
	GSI.uId = function(pre)
	{
		return ( pre || "" ) + "u" + new Date().getTime() + "-" + parseInt(10000*Math.random())
	}
	
/**
 * Fixes a number to minum or maximum values if out of the boundaries passed
 * @param {Number} n		The number to fix
 * @param {Number} min	The minimum value for the number
 * @param {Number} max	The maximum value for the number
 * @return The fixed number
 * @type Number
 */
	GSI.minMax = function(n, min, max)
	{
		if( n < min ) return min;
		if( n > max ) return max;
		return n;
	}
	
//________________________________________________________________
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
//	Arrays

/**
 * Enumerable NameSpace
 * @constructor
 */
	GSI.Enumerable = function() {};
	GSI.NameSpace.create("GSI.Enumerable");
	
/**
 * Match an array item and get its value or index
 * @param {Array} 	a				The array object
 * @param {Object} 	val			The value to find
 * @param {Object} 	asObj		[optional] Return as an object instead of index. default=false
 * @param {Object} 	strict	[optional] Do strict equality comparison. default=false
 * @return Array value or index
 * @type Object or Number
 */
	GSI.Enumerable.find = function( a, val, asObj, strict )
	{
		for( var i=0,len=a.length; i<len; i++)
		{
			if( ( strict && a[i] === val ) || ( !strict && a[i] == val ) ) return asObj ? a[i] : i;
		}
		return asObj ? undefined : -1;  
	}

//________________________________________________________________
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
//	Dynamic Script Loading

/**
 * Scripts namespace
 * @constructor
 */
	GSI.Scripts = function() {};
	GSI.NameSpace.create("GSI.Scripts");
	
/**
 * An array to hold loading scripts
 * @type Array 
 */
	GSI.Scripts._scriptBuffer = [];
	
/**
 * Clear the script buffer
 */
	GSI.Scripts.clear = function()
	{
		this._scriptBuffer = [];
	}

/**
 * The Script.Buffer Class.
 * Used to load scripts dynamically
 * @constructor
 */
	GSI.Scripts.Buffer = function() 
	{
		
		var _scriptBuffer = [];
		var _currentScript = undefined;
		var _loadInitialized = false;
		this.callback = undefined;
		
	/**
	 * Add a script to the buffer
	 * @param {Object} url
	 * @return the URL passed in
	 * @type String
	 */		
		this.add = function( url )
		{
		//	Is the script in the local buffer?
			var u = GSI.Enumerable.find( _scriptBuffer, url, true );
			return u === undefined ? _scriptBuffer.push( url ) : u;
		}
		
	/**
	 * Load the script buffer
	 * @param {Function} callback 	Method to call upon completion
	 */
		this.load = function( callback )
		{	
			if( typeof callback == 'function' ) this.callback = callback;
			
		//	If the buffer is empty, return
		//	Note that pop() occurs below, so we will return only
		//	after the callback is applied
			if( _scriptBuffer.length == 0 )
			{
				if( !_loadInitialized ) this.callback.apply();
				return;
			}
			_loadInitialized = true;
			
		//	Get the next script
			_currentScript = _scriptBuffer.pop();
			
		//	Load the script
			GSI.Scripts.load( _currentScript, this.parseResult.bind(this) );
			
		//	Call the callback if we've loaded all scripts
			if( _scriptBuffer.length == 0 ) 
			{
				setTimeout( this.callback, 200 );
			}
		}
		
	/**
	 * Parse the result of a buffered script load
	 * @param {Object} request the request object
	 */
		this.parseResult = function( request )
		{
			GSI.Scripts.parse( request.responseText, _currentScript );
		//	load the next script
			this.load.apply( this );
		}	
	};
	
/**
 * Dynamically load javascript into the dom
 * via an Ajax Request
 * @param {String} url	The url of the module to load
 * @return the Ajax.Request object
 * @type Object
 */
	GSI.Scripts.load = function( url, successHandler, failHandler )
	{
	//	Create a method to alert the exception
		failHandler = failHandler || function( req ) 
		{
			var s = "failed to load script dependancy\n";
			if( arguments && arguments.callee && arguments.callee.scriptURL ) s += arguments.callee.scriptURL;
			alert(s);
		};
	
	//	Add the script URL to access via arguments.callee.scriptURL
		failHandler.scriptURL = url;
		
	//	Create the Ajax Request
		var request = new Ajax.Request( url + "?ts=" + new Date().getTime(), {
				method: "get",
				onSuccess: successHandler || function(request) { GSI.Scripts.parse( request.responseText, url ) },
				onFailure: failHandler 
			});
			
		return request;
	}
	
/**
 * Parse the script into a DOM script tag
 * @param {String} text			The script text to add to the DOM
 * @param {String} url			The original script URL
 * @return the script object added to the DOM
 * @type Element
 */
	GSI.Scripts.parse = function( text, url )
	{
		var script = GSI.Scripts.find(url);
		
		if( script === undefined )
		{
			script = GSI.$e("script", this.createID(url), false, false, document.getElementsByTagName("head")[0], false );
			script.type = "text/javascript";
			script.text = text;
		}
		return script;
	}

/**
 * Find a script within the DOM by URL
 * @param {String} url 	the url of the script to find
 * @return The script DOM object or undefined 
 * @type Element
 */
	GSI.Scripts.find = function(url)
	{	
	//	get an id from the URL of the script
		var scriptID = GSI.Scripts.createID( url );
		
	//	Check to see if we can find the script with that ID
		var o = document.getElementById( scriptID );
		if( o != undefined ) return o;
		
	//	Otherwise look through the SCRIPT tags for src=attribute
		var els = document.getElementsByTagName("script");
		for( var i=0,len=els.length; i<len; i++ )
		{
			if( els[i].src == url )
			{
				return els[i];
			}
		}
		
		return undefined;
	}

/**
 * Create an ID for a script from a url
 * @param {String} url	The url to convert to an id
 * @return	An id for the script
 * @type String
 */
	GSI.Scripts.createID = function(url)
	{
		url = url.split("/").join(":");
		url = url.split(" ").join("-");
		
		return "SCRIPT-" + url;
	}
	
//________________________________________________________________
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
//	StatusMessage

/**
 * StatusMessage NameSpace
 * @constructor
 */
	GSI.StatusMessage = function(){};
	GSI.NameSpace.create("GSI.StatusMessage");
	
/**
 * The element variable
 * @type Element
 * @private
 */
	GSI.StatusMessage._element = undefined;

/**
 * Get a reference to the element (div) used for status messages
 * @return The div element
 * @type Element
 */
	GSI.StatusMessage.element = function()
	{
		if(this._element === undefined) {
			this._element = GSI.$e( "div", "GSI_StatusDiv", "GSI_Status", false, document.body );
		}
		return this._element;
	}
	
/**
 * Display a status message
 * @param {String} 	html							The HTML to display within the statusMessage
 * @param {Boolean} showLoadingImage	[optional]	show a loading image along with the text
 */
	GSI.StatusMessage.setStatus = function( html, showLoadingImage )
	{	
		this.element().innerHTML = html;
		if( showLoadingImage ) this.element().innerHTML += '<img class="GSI_Status_LoadingImg" src="/images/ajax-rotate.gif" />';
	}
	
/**
 * Show or hide the status message
 * @param {Boolean} visible		
 */
	GSI.StatusMessage.setVisibility = function( visible )
	{
		if( visible ) { 
			this.element().style.display = "";
		} else {
			this.element().style.display = "none"; 
		}
	}
//________________________________________________________________
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
//	Application
/**
 * Application namespace
 * @constructor
 */
	GSI.Application = function() {};
	GSI.NameSpace.create("GSI.Application");
	
	GSI.Application._buffer = [];
	GSI.Application._loaded = [];
	
/**
 * Create an Application
 * @param {String} name
 * @return A reference to the created application
 * @type Object
 */
	GSI.Application.create = function(name)
	{
		if( GSI.Enumerable.find( this._buffer, name ) != -1 ||
				GSI.Enumerable.find( this._loaded, name ) != -1 )
		{
			throw("An application named " + name + " has already been created!");
			return;
		}
		
		this._buffer.push( name );
		return GSI.NameSpace.create( name );
	}
	
/**
 * Load the application buffer
 * @private
 */
	GSI.Application.loadBuffer = function()
	{
		if( this._loaded.length == 0 ) this._buffer.reverse(false);
	
	//	If the buffer is empty, return
		if( this._buffer.length == 0 ) return;
		
	//	Get the next application
		var name = this._buffer.pop(); 
		
	//	Get a reference to the application
		var app = this.find( name );
		
	//	if we have requirements on the app, load them before initializing
		if( app.requires !== undefined && typeof app.requires.pop == 'function' )
		{
			GSI.NameSpace.require( app.requires, function(){
				if( app.initialized !== true ) {
					app.initialized = true;
					app.initialize();
					GSI.Application.loadBuffer();
				}
			});
		} else { app.initialize() };
	
		this._loaded.push( name );
		 
	}
/**
 * Find an application object by name
 * @param {String} name
 * @return An application object with that name
 * @type Object
 */
	GSI.Application.find = function(name)
	{
		var a = name.split(".");
		var o = window;
		for( var i=0,len=a.length;i<len;i++)
		{
			o = o[ a[i] ];
		}
		return o;
	}

//________________________________________________________________
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
//	BrowserDetection

/**
 * GSI Browser NameSpace
 * @constructor
 */
	GSI.Browser = function() {};
	GSI.NameSpace.create("GSI.Browser");
	
	GSI.Browser.versionSearchString = undefined;
	GSI.Browser.browser = undefined;
	GSI.Browser.version = undefined;
	GSI.Browser.OS = undefined;
	
/**
 * Initialize browser detection to get browser, version, and os
 * 
 * Sets the following properties on the GSI.Browser object
 * 		browser: "browserName" || "unknown",
 * 		version: "browser version" || "unknown",
 *  	OS: 		 "OS Name" || "unknown"
 * @private
 */
	GSI.Browser.initialize = function() 
	{
		this.browser = this.searchString(this.browserIdentities) || "unknown";
		this.version = this.searchVersion(navigator.userAgent)
			|| this.searchVersion(navigator.appVersion)
			|| "unknown";
		this.OS = this.searchString(this.platformIdentities) || "an unknown OS";
	}
	
/**
 * Check to see if the browser matches the parameters 
 * @param {String,False} browser	The browser identity to check for or false = don't check
 * @param {String,False} version	The version to check for or false 
 * @param {String,False} OS				The OS to check for	or false
 * @return true/false based on match
 * @type Boolean
 */
	GSI.Browser.is = function( browser, version, OS )
	{
		if( browser && this.browser != browser ) return false;
		if( version && this.version != version ) return false;
		if( OS && this.OS != OS ) return false;
		
		return true;
	}
	
/**
 * Search for browser identity etc
 * @param {Object} data	
 * A data object containing with the following format:
 * (look for a substring to evaluate browser identity)
 * 		string: object.stringValue,
 * 		subString: value to search for
 *  	identity: "Identity of Browser if match"
 *
 * (look for existence of a property to eval browser identity)
 * 		prop: obj.propertyName,
 * 		identity:	"Identity of Browser if match"
 * 
 * Both can contain the value "versionSearch" which will be used
 * instead of the identity value to find the browser version
 *  
 * @return Browser Identity value or undefined
 * @type String
 * @private
 */
	GSI.Browser.searchString = function (data) 
	{
		for (var i=0;i<data.length;i++)	{
			var dataString = data[i].string;
			var dataProp = data[i].prop;
			this.versionSearchString = data[i].versionSearch || data[i].identity;
			if (dataString) {
				if (dataString.indexOf(data[i].subString) != -1)
					return data[i].identity;
			}
			else if (dataProp)
				return data[i].identity;
		}
	}
	
/**
 * Search for a version of the browser
 * @param {String} dataString	
 * @return The version number
 * @type Number
 */
	GSI.Browser.searchVersion = function (dataString) 
	{
		var index = dataString.indexOf(this.versionSearchString);
		if (index == -1) return;
		return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
	}
	
/**
 * The browser identity array
 * This is used to identify browsers ( uses Browser.searchString )
 * @type Array
 */
	GSI.Browser.browserIdentities = [
		{ 	
			string: navigator.userAgent,
			subString: "OmniWeb",
			versionSearch: "OmniWeb/",
			identity: "OmniWeb"
		},
		{
			string: navigator.vendor,
			subString: "Apple",
			identity: "Safari"
		},
		{
			prop: window.opera,
			identity: "Opera"
		},
		{
			string: navigator.vendor,
			subString: "iCab",
			identity: "iCab"
		},
		{
			string: navigator.vendor,
			subString: "KDE",
			identity: "Konqueror"
		},
		{
			string: navigator.userAgent,
			subString: "Firefox",
			identity: "Firefox"
		},
		{
			string: navigator.vendor,
			subString: "Camino",
			identity: "Camino"
		},
		{		// for newer Netscapes (6+)
			string: navigator.userAgent,
			subString: "Netscape",
			identity: "Netscape"
		},
		{
			string: navigator.userAgent,
			subString: "MSIE",
			identity: "IE",
			versionSearch: "MSIE"
		},
		{
			string: navigator.userAgent,
			subString: "Gecko",
			identity: "Mozilla",
			versionSearch: "rv"
		},
		{ 		// for older Netscapes (4-)
			string: navigator.userAgent,
			subString: "Mozilla",
			identity: "Netscape",
			versionSearch: "Mozilla"
		}
	];
	
/**
 * The platform identity array
 * This is used to identify OS names
 * @type Array
 */
	GSI.Browser.platformIdentities = [
		{
			string: navigator.platform,
			subString: "Win",
			identity: "Windows"
		},
		{
			string: navigator.platform,
			subString: "Mac",
			identity: "Mac"
		},
		{
			string: navigator.platform,
			subString: "Linux",
			identity: "Linux"
		}
	];

//	Initialize the GSI framework
	GSI.initialize();
