// JavaScript Document
	/////////////////////////////////////////////////
	/// ---------------------------------------------
	///  FWK v2
	/// ---------------------------------------------
	/////////////////////////////////////////////////

	/// Basic constants for browser detection and such
	document.isIE       = ( document.all ) ? true : false;
	document.isSafari   = ( navigator.userAgent.toLowerCase().indexOf(   'safari') < 0 ) ? false : true;
	document.isMac      = ( navigator.userAgent.toLowerCase().indexOf('macintosh') < 0 ) ? false : true;
	document.serviceURL = "/services/gateway/";

	/*remove*/ try
	/*remove*/ {
	/*remove*/		console.warn ( "FWK LOADED" );
	/*remove*/ }
	/*remove*/ catch ( e )
	/*remove*/ {
	/*remove*/ 		var console	 = new Object ();
	/*remove*/ 		console.warn = function  (){};
	/*remove*/ }

	var FWK_AllTabs = new Array ();

	/// getItem is used as shorthand for getElementById
	function getItem ( tID )
	{
		try {
			return document.getElementById( tID );
		}catch(e){
			/*remove*/ try{ console.warn( "Element:" + tID + ", not found" ); }catch(e){ alert( "can't find it" ); };
			return false;
		}
	}
	
	
	/// Dont ask.
	var FWK_Extend = function ( subClass, baseClass )
	{
	   function inheritance() {};
	   inheritance.prototype = baseClass.prototype;
	
	   subClass.prototype             = new inheritance();
	   subClass.prototype.constructor = subClass;
	   subClass.baseConstructor       = baseClass;
	   subClass.superClass            = baseClass.prototype;
	};
	
	
	/// getClassNamedItemWithin grabs any element with the classname of
	function getClassNamedItemWithin ( tClassName, tObject )
	{
		var theObject;
		
		/// cycle through its children and get the one with the classname
		for ( var tItem = 0; tItem <  tObject.childNodes.length; tItem ++ )
		{
			/// check to see if its the one were looking for
			if ( tObject.childNodes[ tItem ].className == tClassName )	
			{
				/// return a reference to the object
				theObject = tObject.childNodes[ tItem ];
			}
		}
		
		if ( theObject != null )
		{
			return theObject;
		}
		else
		{
			/// obviously it wasn't found, so pass back false
			/*remove*/ try{ console.warn( "Element with the class name " + tClassName + ", not found" ); }catch(e){ alert( "Element with the class name " + tClassName + ", not found" ); };
			return false;
		};
	};
	
	
	///	Creates a second level execution object allowing IE to
	/// pass by reference in functions it normally wouldn't support
	Function.prototype.bind = function( tObject, tArgs )
	{
		var method   = this;
		var object   = tObject;
		var argument = tArgs;

		var tArray = new Array();
		tArray[0] = tArgs;

		return function()
		{
			return method.apply ( object, tArray );
		};
	};
	
	
	/// Two small functions giving direct access to show and hide
	/// functionality on page elements
	var hide = function ( tObject )
	{
		/// Check to see if an object was supplied,
		/// if not, use the string to get the object
		if ( isString ( tObject ) ) {
			tObject = getItem( tObject );
		}
		
		if ( tObject.className.indexOf( "hidden" ) > -1 )
		{  }
		else
		{ tObject.className += " hidden"; }
	}
	var show = function ( tObject )
	{
		/// Check to see if an object was supplied,
		/// if not, use the string to get the object
		if ( isString ( tObject ) ) {
			tObject = getItem( tObject );
		}
		
		if ( tObject.className.indexOf( "hidden" ) > -1 )
		{
			var tClasses = tObject.className.split( " " );
			for ( var i = 0; i < tClasses.length; i ++ )
			{
				if ( tClasses[i] == "hidden" )
				{
					tClasses[i] = null;
				}
			}
			
			tClasses = tClasses.join( " " );
			tObject.className = tClasses;
		}
	}
	
	
	/// New Element is used as shorthand to createElement
	function newElement ( tType )
	{
		return document.createElement( tType );
	}
	function killElement ( tElement )
	{
		var tThrowAway = tElement.parentNode.removeChild( tElement );
	}
	
	
	/// isString checks to see if the supplied variable is a string or not
	function isString ( tObject )
	{
		return ( typeof tObject == "String" || typeof tObject == "string" ) ? true : false;
	}
	
	
	/// get all the child form elements for an object
	function getFormElements ( tObject )
	{
		/// Check to see if an object was supplied,
		/// if not, use the string to get the object
		if ( isString ( tObject ) ) {
			tObject = getItem( tObject );
		}
		
		/// get all the form elements
		var tArray1 = tObject.getElementsByTagName(    "input" );
		var tArray2 = tObject.getElementsByTagName(   "select" );
		var tArray3 = tObject.getElementsByTagName( "textarea" );
		
		/// join all the arrays together
		var tArray = new Array ();
		
		var j = 0;
		for ( var i = 0; i < tArray1.length; i ++ )
		{
			tArray[j] = tArray1[i];
			j ++
		}
		for ( var i = 0; i < tArray2.length; i ++ )
		{
			tArray[j] = tArray2[i];
			j ++
		}
		for ( var i = 0; i < tArray3.length; i ++ )
		{
			tArray[j] = tArray3[i];
			j ++
		}
		
		return tArray;
	}
	
	
	/// Modulus, used in the calendar amongst other things
	function Mod(X, Y)
	{
    	return X - Math.floor(X / Y) * Y;
	}
	
	
	/// Modulus, used in the calendar amongst other things
	function copyArray ( tArray )
	{
		var tArray2 = new Array ();
		for ( var i in tArray )
		{
			tArray2[i] = tArray[i];
		}
		
		return tArray2;
	}
	
	
	/// Parse JSON into a JS Object
	function FWK_JSON ( tData )
	{
		try {
			return eval( '(' + tData + ')' );
		}catch (e){
			/*remove*/ alert ( "JSON string invalid" );
			return false;
		}
	}


	/// Parse XML into a JS Object
	function FWK_XML ( tData )
	{
		/// TODO - find a good parser
		alert( "XML Parser not yet implemented" );
		return tData;
	}
	
	
	/// Redirect the user
	function FWK_Goto ( tUrl )
	{
		if ( tUrl.indexOf ( "#" ) > -1 )
		{
			var tName = tUrl.split ( "#" )[1];
			
			for ( var i = 0; i < FWK_AllTabs.length; i ++ )
			{
				if ( FWK_AllTabs[i].respondsToTabName ( tName ) > -1 )
				{
					FWK_AllTabs[i].selectTabWithName ( tName );
				}
			}
		}
		
		window.location = tUrl;	
	}
	
	
	/// Redirect the user
	function FWK_LoadArea ( tUrl, tArea )
	{
		var tLoad  = new Object ( );
		var tArray = new Array  ( );
		var tAjax  = new FWK_Ajax ( tLoad );
		
		tArray.push ( Array ( "service[format]", "json" ) );
		
		if ( isString ( tArea ) )
		{
			tArea = getItem ( tArea );
		}
		tLoad.area = tArea;
		
		tLoad.onAjaxTrigger  = function (       ) { };
		tLoad.onAjaxResponse = function ( tData ) { this.area.innerHTML = tData };
		tLoad.onAjaxError    = function ( tData ) { alert ( "There was an issue with your request." ); };
		
		tAjax.makeRequest ( tUrl, tArray );
	}
	
	
	/// Replace divs with ads
	function FWK_setAd ( tArea, tAd )
	{
		if ( getItem( tArea ) )
		{
			getItem( tArea ).innerHTML = tAd;
		}
	}
	
	
	/// Change to the items city
	function FWK_changeCity ( tValue )
	{
		var tLocation = String ( window.location )
		
		if ( tLocation.indexOf( "?" ) >= 0 )
		{
			window.location = String( window.location ) + "&city=" + tValue;
		}
		else
		{
			window.location = String( window.location ) + "?city=" + tValue;
		}
	}
	
	
	/// Change to the items city
	function FWK_selectItemInList ( tList, tItem )
	{
		if ( typeof tList == "String" || typeof tList == "string" ) {
			tList = getItem( tList );
		}
		
		for ( var i = 0; i < tList.options.length; i ++ )
		{
			if ( tList.options[i].value == tItem )
			{
				tList.selectedIndex = i;
				break;
			}
		}
	}
	
	
	/// Makes sure that all characters are ok to post through ajax
	function FWK_treatForPost ( tString )
	{
		tString = encodeURIComponent ( tString );
		return tString;
	}
	

	/// Returns the X, Y, W & H of an object
	function FWK_Position ( tObject )
	{
		if ( isString ( tObject ) )
		{
			tObject = getItem ( tObject );
		}
		
		var x,w,y,h;
		if ( document.getBoxObjectFor )
		{
			x =  tObject.offsetLeft;
			w =  tObject.offsetWidth;
			y =  tObject.offsetTop;
			h =  tObject.offsetHeight;
		}
		else if ( tObject.getBoundingClientRect )
		{
			var tBox = tObject.getBoundingClientRect();
			x =  tBox.left;
			w =  tBox.right - tBox.left;
			y =  tBox.top;
			h =  tBox.bottom - tBox.top;
		}
		
		var tObject = new Object ();
		tObject.width  = w;
		tObject.height = h;
		tObject.top    = y;
		tObject.left   = x;
		
		return tObject;
	}

	
	
	/// Look-Ups
	var FWK_Days   = Array ( "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" );
	var FWK_Months = Array ( "January", "Febuary", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" );
	
	
	
	
	
	///////////////////////////////////////////////////////////
	///
	///	A bit of legacy framework
	///
	///////////////////////////////////////////////////////////
	var DataSource=function ( ){this.data = new Object();};
	DataSource.prototype.clearData=function ( ){this.data = new Object();};
	DataSource.prototype.loadFromJSON=function ( tJSON ){this.data = eval ( tJSON );};
	
	
	
	
	
	///////////////////////////////////////////////////////////
	///
	///	FWK Menu
	///
	/// -------------------------------------------------------
	///	Used to create drop down menus such as site navigation
	///
	///////////////////////////////////////////////////////////
	var FWK_Menu = function ( tObject )
	{
		if ( isString ( tObject ) )
		{
			tObject = getItem ( tObject );
		}
		
		this.me = tObject;
	}
	
	FWK_Menu.prototype.add = function ( tSection )
	{
		this.me.appendChild ( tSection.build() );
	}
	
	FWK_Menu.prototype.init = function ()
	{
		/// cycle through the list items
		/// this part is IE only
		if ( document.isIE )
		{
			var tItems = this.me.getElementsByTagName( "li" );
			for ( var i = 0; i < tItems.length; i ++ )
			{
				/// make sure the one were manipulating is an item
				if ( tItems[i].className == "item" && !tItems[i].attributes.getNamedItem( "emptyMenu" ) )
				{
					/// on mouse over, show the drop down
					tItems[i].onmouseover = function ()
					{
						//this.getElementsByTagName( "ul" )[0].className = "open"; 
						this.className    = "open";
						this.style.zIndex = 9999999;
					};
					
					/// on mouse out, put it away
					tItems[i].onmouseout = function ()
					{
						//this.getElementsByTagName( "ul" )[0].className = ""; 
						this.className = "";
					};
				}
			}
		}
		else
		{
			var tItems = this.me.getElementsByTagName( "li" );
			for ( var i = 0; i < tItems.length; i ++ )
			{
				/// make sure the one were manipulating is an item
				if ( tItems[i].className == "item" && !tItems[i].attributes.getNamedItem( "emptyMenu" ) )
				{
					/// on mouse over, show the drop down
					tItems[i].onmouseover = function ()
					{
						this.style.zIndex = 9999999;
					};
				}
			}
		}
		
		
		/// Now go through and get all the sub items
		/// this part is for all browsers, and only required if we want messages to display
		var tItems = this.me.getElementsByTagName( "li" );
		
		for ( var i = 0; i < tItems.length; i ++ )
		{
			/// make sure its a menu item
			if ( String ( tItems[i].className ) == "item" )
			{
				/// cycle through its children
				var tItemsSub = tItems[i].getElementsByTagName( "li" );
				for ( var j = 0; j < tItemsSub.length; j++ )
				{
					/// make sure the object were talking to is a HTML element
					/// this fix is required for IE, it passes through function calls as part of the object
					if ( tItemsSub[j].nodeName && tItemsSub[j].className != "description" )
					{
						tItemsSub[j].messageArea = getClassNamedItemWithin( "description", tItems[i].childNodes[1] );
						
						/// setup the mouse over function
						/// when the user puts their mouse over the sub item, it will change the message to the one set to the nav item
						/// if theres none, nothing will be displayed
						tItemsSub[j].onmouseover = function ()
						{							
							if ( this.attributes.getNamedItem( "message" ) )
							{
								this.messageArea.innerHTML = this.attributes.getNamedItem( "message" ).nodeValue;
							}
							else
							{
								this.messageArea.innerHTML = "";
							};
						};
					}
				}
			}
		}
		
		try
		{
			menuComplete();
		}
		catch(e){};
	}
	
	FWK_Menu.prototype.select = function ( tText )
	{		
		var tItems = this.me.getElementsByTagName( "li" );
		for ( var i = 0; i < tItems.length; i ++ )
		{
			/// make sure the one were manipulating is an item
			if ( tItems[i].className == "item" && String(tItems[i].innerHTML).indexOf ( ">" + tText + "<" ) > -1 )
			{
				// select it
				tItems[i].getElementsByTagName("a")[0].className="selected";
			}
		}
	}
	
	var FWK_Menu_Section = function ( tName, tURL )
	{
		this.data = new Array ();
		this.name = tName;
		this.url  = tURL;
	}
	
	FWK_Menu_Section.prototype.add = function ( tName, tURL, tDescription,  tHighlighted )
	{
		this.data.push ( Array ( tName, tURL, tDescription, tHighlighted ) );
	}
	
	FWK_Menu_Section.prototype.build = function (  )
	{
		// Create the Drop Down
		tItem = newElement ( "li" );
		tItem.className = "item";
		
		// Create the main link
		tLink = newElement ( "a" );
		tLink.href = this.url;
		tLink.innerHTML = this.name;
		
		// add the link to the drop down
		tItem.appendChild ( tLink );
		
		// create the menu items
		tSub = newElement ( "ul" );
		for ( var i in this.data )
		{
			tEntry = newElement ( "li" );
			
			// is it highlighted?
			if ( this.data[i][3] )
			{
				tEntry.className = "highlighted";
			}
			
			tLink = newElement ( "a" );
			tLink.href = this.data[i][1];
			tLink.innerHTML = this.data[i][0];
			
			tEntry.setAttribute ( "message", this.data[i][2] );
			tEntry.appendChild ( tLink );
			
			tSub.appendChild ( tEntry );
		}
		
		tEntry = newElement ( "li" );
		tEntry.className = "description";
		tSub.appendChild ( tEntry );
		
		tItem.appendChild( tSub );
		
		return tItem;
	}
		
	
	
	
	
	
	/////////////////////////////////////////////////////////////////
	///
	///	FWK Timer
	///
	/// -------------------------------------------------------------
	///	A simple counter that can be used as a basis for animations
	/// counts from 0 to 1 within a given time scale, triggers
	/// are sent back to the owner on start, complete and frame
	/// there is also the ability to loop, and get a eased percentage
	///
	/// There are three callbacks registered, they are:
	///  - onTimerStart     <- called when the timer starts
	///  - onTimerFrame     <- called when the timer has an interval
	///  - onTimerComplete  <- called when the timer is over
	///
	/////////////////////////////////////////////////////////////////
	var FWK_Timer = function ( tDuration, tObject )
	{
		this.frameInterval = 20;
		this.timer = null;
		this.currentCount = 0;
		
		this.me = this;
		this.object = tObject;
		this.duration = ( Number(tDuration) * 1000 ) / this.frameInterval;
		
		this.loop = false;
	};

	/// starts the timer
	FWK_Timer.prototype.start = function ()
	{
		this.timer = setInterval( this.onTime.bind(this), this.frameInterval );
		this.object.onTimerStart.apply( this.object );
	};

	/// starts the timer in reverse [ starts at 100% and counts down ]
	FWK_Timer.prototype.startReverse = function ()
	{
		this.currentCount = this.duration;
		
		this.timer = setInterval( this.onReverseTime.bind(this), this.frameInterval );
		this.object.onTimerStart.apply( this.object );
	};
	
	/// called when the timer has ended
	FWK_Timer.prototype.ended = function ()
	{
		this.object.onTimerComplete.apply( this.object );
	};

	/// called by the setInterval function when counting up
	FWK_Timer.prototype.onTime = function ()
	{	
		this.currentCount ++;

		var tPercentComplete = ( this.currentCount / this.duration );
		var tArgs = new Array();
		tArgs[0]  = tPercentComplete;
		tArgs[1]  = this.duration;
		tArgs[2]  = ( ( ( Math.cos( tPercentComplete * Math.PI ) * -1 ) + 1 ) / 2 );

		this.object.onTimerFrame.apply ( this.object, tArgs );

		if ( this.currentCount >= this.duration )
		{
			clearInterval(this.timer);

			if ( this.loop )
			{
				this.timer = setInterval( this.onReverseTime.bind( this ), this.frameInterval );
			}
			else
			{
				this.ended();
			}
		}
	};

	/// called by the setInterval function when counting down
	FWK_Timer.prototype.onReverseTime = function ( )
	{
		this.currentCount --;

		var tPercentComplete = ( this.currentCount / this.duration );
		var tArgs = new Array();
		tArgs[0]  = tPercentComplete;
		tArgs[1]  = this.duration;
		tArgs[2]  = ( ( ( Math.cos( tPercentComplete * Math.PI ) * -1 ) + 1 ) / 2 );

		this.object.onTimerFrame.apply ( this.object, tArgs );

		if ( this.currentCount <= 0 )
		{
			clearInterval(this.timer);

			if ( this.loop )
			{
				this.timer = setInterval( this.onTime.bind( this ), this.frameInterval );
			}
			else
			{
				this.ended();
			}
		}
	};
	
	/// Resets the timer, and throws it back to Zero
	FWK_Timer.prototype.reset = function ()
	{
		// removes the timer
		clearInterval ( this.timer );
		
		this.timer		  = null;
		this.currentCount = 0;
	};
	
	
	
	
	
	
	///////////////////////////////////////////////////////////////////////////////////////
	///
	///	FWK QuickTool
	///
	/// -----------------------------------------------------------------------------------
	/// Quick Tools are used as a core part of the SameSame interface, they
	/// need to handle opening and closing, as well as having default states.
	///
	/// There is a set HTML structure required to init the QuickTools: [XXX = unique name]
	///
	///	<div id="quickTool_XXX"> 
	///
	/// 	<h3 class="heading">
	///			XXX <- Heading
	///		</h3>
	///		<span class="status"></span>
	///
	///		<div class="content">
	///			XXX <- Tool Content Here
	///		</div>
	///		
	/// </div>
	///
	///////////////////////////////////////////////////////////////////////////////////////
	var FWK_QuickTool = function ( tObject, tDefault )
	{
		/// Check to see if an object was supplied,
		/// if not, use the string to get the object
		if ( isString ( tObject ) ) {
			tObject = getItem( tObject );
		}
		
		
		/// set the constants.
		this.me     = tObject;
		this.isOpen = tDefault;
		this.timer  = new FWK_Timer ( 0.25, this );
		this.isAnimating = false;
		this.hasRun = false;
		
		this.subClass = this.me.className + " ";
		
		/// Find all the elements
		this.heading = getClassNamedItemWithin( "heading", this.me );
		this.status  = getClassNamedItemWithin(  "status", this.me );
		this.content = getClassNamedItemWithin( "content", this.me );
		
		
		/// Get the main heading
		this.heading.main = this.heading.innerHTML;
		if ( this.heading.attributes.getNamedItem( "toggle" ) )
		{
			this.heading.alternate = this.heading.attributes.getNamedItem( "toggle" ).nodeValue;
		}
		else
		{
			this.heading.alternate = this.heading.main;
		}
		
		
		/// Get the Dimensions
		this.content.height = this.content.offsetHeight;
		this.content.width  = this.content.offsetWidth;
		
		
		// setup the interface
		this.setInterface();
		
		
		/// Setup the triggers
		this.heading.parent  = this;
		this.status.parent   = this;
		this.heading.onclick = function () { this.parent.toggle.apply( this.parent ); };
		this.status.onclick  = function () { this.parent.toggle.apply( this.parent ); };
	};

	/// Required callbacks for the timer, used to ensure there aren't two animations occuring at once
	FWK_QuickTool.prototype.onTimerStart  = function (){ this.isAnimating =  true; };
	
	/// required for the callbacks, also used to fix up any dodgy maths that can result from the trig
	FWK_QuickTool.prototype.onTimerComplete = function ()
	{
		this.isAnimating = false;
		
		if ( this.isOpen )
		{
			this.content.style.height = this.content.height;
		}
		else
		{
			this.content.style.height = "0px";
		}
	};
	
	/// resets the height of a quicktool, allowing for dynamic resizing
	FWK_QuickTool.prototype.resetHeight = function ()
	{
		this.content.style.height = "auto";
		this.content.height       = this.content.offsetHeight;
		this.content.width        = this.content.offsetWidth;
		this.content.style.height = this.content.height;
	};

	/// Required callback for the timer, makes the quick tool block animate
	FWK_QuickTool.prototype.onTimerFrame = function ( tTime, tDuration, tEased )
	{
		this.content.style.height = String( tEased * this.content.height ) + "px";
	};

	/// triggers the animation & open/closing of the quick tools
	FWK_QuickTool.prototype.toggle = function ()
	{
		/// check to see if there is an animation already running
		if ( !this.isAnimating )
		{
			
			// if its already open, close it
			if ( this.isOpen ) {
				this.timer.startReverse();
				
			// else, open it
			} else {
				this.timer.start(); }
	
			// change the status
			this.isOpen = !this.isOpen;	
		
			// update the rest of the interface
			this.setInterface();
		}
	};
	
	/// updates the interface with the new setting
	FWK_QuickTool.prototype.setInterface = function ()
	{
		if ( this.isOpen )
		{
			this.heading.innerHTML = this.heading.alternate;
			
			this.heading.title = "Click to close area";
			this.status.title  = this.heading.title;
			
			this.me.className = this.subClass + "open";
			
			this.status.innerHTML = "-";
			
			if ( !this.hasRun )
			{
				this.content.style.height = this.content.height + "px";
				
				this.hasRun = true;
			}
		}
		else
		{
			this.heading.innerHTML = this.heading.main;
			
			this.heading.title = "Click to open area";
			this.status.title  = this.heading.title;
			
			this.me.className = this.subClass + "closed";
			
			this.status.innerHTML = "+";
			
			if ( !this.hasRun )
			{
				this.content.style.height = "0px";
				
				this.hasRun = true
			}
		}
	}
	
	
	
	
	
	
	///////////////////////////////////////////////////////////////////////////////////////
	///
	/// FWK Tabs
	///
	/// -----------------------------------------------------------------------------------
	/// Tabs allow you to quickly turn a UL list into a fully functional tab bar
	/// tabs can be preselected by passing an anchor through the URL, as well as setting
	/// a default through custom element attributes.
	///
	/// Currently, tabs only allow you to take href links and JS function calls as actions
	///
	/// There is a set HTML structure required to init the Tabs: [XXX = unique name]
	///
	///	<ul id="tabs_XXX">
	///		<li action="link" name="tab1">
	///			<a href="">
	///				Tab #1
	///			</a>
	///		</li>
	///		<li action="link" name="tab2">
	///			<a href="">
	///				Tab #2
	///			</a>
	///		</li>
	///		<li action="javascript:function_a" name="tab3" default="default">
	///			Tab #3
	///		</li>
	///		<li action="javascript:function_b" name="tab4">
	///			Tab #4
	///		</li>
	///	</ul>
	///
	/// the action tells this class what needs to happen when it gets clicked, the 'link'
	/// type doesn't take any action at all, and is just there as a placeholder to 
	/// make it easy to read. the 'javascript' one however offers the name of the function
	/// to be called. The function will be executed within the scope of the window.
	///
	/// If a selected tab is not supplied through the window.location, the one with default
	/// will be selected, failing that, the first one will be selected. Please ensure you
	/// use the name supplied in the LI tag as the anchor, as it is the UID.
	///
	///////////////////////////////////////////////////////////////////////////////////////
	var FWK_Tabs = function ( tObject )
	{
		/// Check to see if an object was supplied,
		/// if not, use the string to get the object
		if ( isString ( tObject ) ) {
			tObject = getItem( tObject );
		}
		
		/// set the constants.
		this.me = tObject;
		
		/// setup all the tabs
		this.setupTabs();
		
		/// check to see if the user wants one preselected
		this.selection = String ( window.location ).split ( "#" )[1];
		if ( this.selection )
		{
			this.selectTabWithName ( this.selection );
		}
		else
		{
			this.selectDefaultTab ();
		}
	}
	
	/// builds all the tabs and their actions
	FWK_Tabs.prototype.setupTabs = function ()
	{
		/// cycle through all the tabs
		var tItems = this.me.getElementsByTagName( "li" );
		for ( var i = 0; i < tItems.length; i ++ )
		{
			// check to see if it has a javascript action assigned
			if ( tItems[i].attributes.getNamedItem( "action" ).nodeValue.indexOf( "javascript" ) > -1 )
			{
				var tArray = new Array();
				tArray[0]  = i;
				
				tItems[i].onclick = this.activateTab.bind( this, i );
			}
		}
	}
	
	/// triggered by the user selecting a tab
	FWK_Tabs.prototype.activateTab = function ( tID )
	{
		// track down the tab that was clicked
		var tItems = this.me.getElementsByTagName( "li" );
		var tItem  = tItems[ tID ];
		
		// turn off all other tabs
		this.disableAllTabs();
		
		// activate it
		tItem.className = "active";
		
		window.location = ( String(window.location).split("#")[0] ) + "#" + tItem.attributes.getNamedItem( "name" ).nodeValue
		
		// call its function [ cause we know its a JS tab ]
		var tFunction = tItem.attributes.getNamedItem( "action" ).nodeValue.split(":")[1];
		eval ( tFunction + "();" );
	}
	
	/// cycles through the tabs and deselects them all
	FWK_Tabs.prototype.disableAllTabs = function ()
	{
		/// cycle through all the tabs
		var tItems = this.me.getElementsByTagName( "li" );
		for ( var i = 0; i < tItems.length; i ++ )
		{
			/// remove their class names
			tItems[i].className = "";
		}
	}
	
	/// searches through the tabs and selects the one requested
	FWK_Tabs.prototype.selectTabWithName = function ( tName )
	{
		/// disable any if selected
		this.disableAllTabs();
		
		/// cycle through all the tabs
		var tItems = this.me.getElementsByTagName( "li" );
		var wasSuccessfull = false;
		var tabID = 0;
		for ( var i = 0; i < tItems.length; i ++ )
		{
			/// check if it has the default attribute
			if ( tItems[i].attributes.getNamedItem( "name" ).nodeValue == tName )
			{
				// activate it
				tItems[i].className = "active";
				wasSuccessfull = true;
				tabID = i;
			}
		}
		
		if ( !wasSuccessfull )
		{
			this.selectDefaultTab();
		}
		else
		{
			this.activateTab ( tabID );
		}
	}
	
	/// searches through the tabs and selects the one requested
	FWK_Tabs.prototype.respondsToTabName = function ( tName )
	{
		/// cycle through all the tabs
		var tItems = this.me.getElementsByTagName( "li" );
		var wasSuccessfull = -1;
		var tabID = 0;
		for ( var i = 0; i < tItems.length; i ++ )
		{
			/// check if it has the default attribute
			if ( tItems[i].attributes.getNamedItem( "name" ).nodeValue == tName )
			{
				wasSuccessfull = i;
			}
		}
		
		return wasSuccessfull;
	}

	/// finds the default tab, or selects the first
	FWK_Tabs.prototype.selectDefaultTab = function ()
	{		
		/// disable any if selected
		this.disableAllTabs();
		
		/// cycle through all the tabs
		var tItems = this.me.getElementsByTagName( "li" );
		var wasSuccessfull = false;
		for ( var i = 0; i < tItems.length; i ++ )
		{
			/// check if it has the default attribute
			if ( tItems[i].attributes.getNamedItem( "default" ) )
			{
				// activate it
				tItems[i].className = "active";
				wasSuccessfull = true;
			}
		}
		
		if ( ! wasSuccessfull )
		{
			tItems[0].className = "active";
		}
	}
	
	
	
	
	
	
	////////////////////////////////////////////////////////////////////////
	///
	///	FWK Ajax
	///
	/// ---------------------------------------------------------------------
	///	Allows javascript to communicate with the live server
	/// Note, all requests are made through a hybrid of GET and POST actions
	/// It is specifically designed to work with the TSA Services system
	///
	/// FWK Ajax has a timeout build in, by default the timeout is set to
	/// 10 seconds. Upon reaching the timeout, the response is trashed
	/// and an error thrown [ 408 ]
	///
	/// There is only three required callbacks:
	/// - onAjaxTrigger   <- Called when an ajax call has gone out
	/// - onAjaxResponse  <- Called when the server has responded
	/// - onAjaxError     <- Called when the reponse had an error
	///
	///	FWK Ajax uses the W3 error spec to report issues with the TSA Service
	/// Framework. They are:
	/// 200 - OK 			    <- 100% A-Ok
	/// 204 - No Content		<- The required object does not exist
	/// 400 - Bad Request 	    <- Something Bad Happened
	/// 401 - Unauthorized 	    <- Need more Authorisation
	/// 404 - Not Found 	    <- The Service is wrong, or URL bad
	/// 406 - Not Acceptable    <- Argument syntax is invalid
	/// 408 - Request Time-Out  <- Timeout
	/// 500 - Server Error		<- Server Issues
	///
	/// If the user has a old browser which doesn't support Ajax, they are
	/// re-directed to /support/oldbrowser  <- MUST ENSURE IT EXISTS
	///
	/// Each request can contain a format, by default its JSON, but it could
	/// be XML, CSV or HTML if needed. FWK Ajax anticipates the data to come
	/// back in the same format, however, the TSA Services can override that
	/// setting and supply a different format in the HTTP Request Headers
	/// FWK Ajax automatically uses the suited parser to decode the content
	///
	////////////////////////////////////////////////////////////////////////
	var FWK_Ajax = function ( tObject )
	{
		/// Check to see if an object was supplied,
		/// if not, use the string to get the object
		if ( isString ( tObject ) ) {
			tObject = getItem( tObject );
		}

		/// set the constants
		this.me      = tObject;
		this.timer   = new FWK_Timer ( 10.0, this );
		this.request = null;
		
		// Booleans
		this.isProcessing    = false;
		this.hasBeenCanceled = false;
	}
	
	/// Called to make a Service request
	FWK_Ajax.prototype.makeRequest = function ( tURL, tVars )
	{
		/// set the switches
		this.hasBeenCanceled = false;
		this.isProcessing    = true;
		
		// call the trigger
		this.me.onAjaxTrigger.apply ( this.me );
		
		/// Create the request object
		if ( document.isIE )
		{
			try { this.request = new ActiveXObject("Msxml2.XMLHTTP");
			} catch(e) {
				try { this.request = new ActiveXObject("Microsoft.XMLHTTP"); 
				} catch(e) {} }
		}
		else
		{
			try {
				this.request = new XMLHttpRequest();
			} catch(e){}
		}
		
		
		// check to see if the request object was set
		if ( this.request == null ) {
		
			window.location = "/about#upgrade";
			
		} else {
		
			// make the vars string
			var tParams = "";
			var tFormat = null;
			for ( var tItem in tVars )
			{
				tParams += tVars[tItem][0] + "=" + tVars[tItem][1] + "&"
			
				// see if this is the format one
				if ( tVars[tItem][0] == "service[format]" )
				{
					tFormat = tVars[tItem][0];
				}
			}


			// see if the format has been specified, else, set to json
			tFormat = ( tFormat != null ) ? tFormat : "json";
		
		
			// remove the trailing ampersands from the post variables
			tParams = tParams.substr( 0, tParams.length - 1 )


			// override the mime type if we can [ IE doesn't let you ]
			try {
				this.request.overrideMimeType ( 'text/' + tFormat );
			} catch (e) {}
		
		
			/// start the timer
			this.timer.start();
			
			this.request.onreadystatechange = this.acceptResponse.bind ( this );
			var tMethod = ( this.method ) ? this.method : "POST";
			
			if ( tMethod != "POST" )
			{
				this.request.open ( tMethod, tURL + "?" + tParams, true );
				this.request.send ( "" );
			}
			else
			{
				this.request.open ( tMethod, tURL, true );
				this.request.setRequestHeader("Content-type",   "application/x-www-form-urlencoded;charset=utf-8")
				this.request.setRequestHeader("Content-length", tParams.length)
				this.request.setRequestHeader("Connection",     "close")
				this.request.send ( tParams )
			}
		}
	}
	
	/// Called by the XML Request Object once a response has arrived
	FWK_Ajax.prototype.acceptResponse = function ()
	{
		/// Check to see if the request is complete
		if ( this.request.readyState == 4 )
		{		
			/// stop the timer
			this.timer.reset();
			this.hasBeenCanceled = false;
			
			/// find what type of response we have received
			switch ( this.request.status )
			{
				/// 200 <- Means everything went A-OK
				case 200:
				
					var tData = null;
				
					/// is the data returned JSON?
					if ( this.request.getResponseHeader("Content-Type").indexOf( "json" ) > 0 )
					{
						tData = FWK_JSON ( this.request.responseText );
					}
					// is the data returned XML?
					else if ( this.request.getResponseHeader("Content-Type").indexOf( "xml" ) > 0 )
					{
						tData = FWK_XML ( this.request.responseText );
					}
					// must be something else
					else
					{
						tData = this.request.responseText
					}
				
					// collate the data
					var tArray = new Array();
					tArray[0] = tData;
				
					// trigger the callback
					this.me.onAjaxResponse.apply( this.me, tArray );
					
					break;
				
				/// 400, 401, 404 & 408 <- Means something went wrong...		
				case 204:
				case 1223:
				case 400:
				case 401:
				case 404:
				case 406:
				case 408:
				case 500:
				
					// collate the data
					var tArray = new Array();
					tArray[0] = this.request.status;
				
					// trigger the callback
					this.me.onAjaxError.apply( this.me, tArray );
				
					break;
				
				/// Something else happened....
				default:
					alert ( "The request you have made has returned some unexpected data: " + this.request.status );
			}
		
			// set the switches
			this.isProcessing = false;
			this.request      = null;
		}
	}
	
	/// Triggered by the timer if the request takes too long
	/// defaulted to a 10 second time out
	FWK_Ajax.prototype.cancelRequest = function ()
	{
		// check to see if it still has't responded
		if ( this.isProcessing )
		{
			// cancel the processing
			this.isProcessing = false;
			
			// Create the var array
			var tArray = new Array();
			tArray[0]  = 408;
			
			// pass the error to the callee
			this.me.onAjaxError.apply( this.me, tArray );
		}
	}
	
	/// Various callbacks required for the timer object
	FWK_Ajax.prototype.onTimerStart    = function (){};
	FWK_Ajax.prototype.onTimerFrame    = function (){};
	FWK_Ajax.prototype.onTimerComplete = function ()
	{
		// check to see if there has been a response yet
 		if ( this.isProcessing ) {
	
			// cancel the request
			this.cancelRequest();
		}
	};
	
	
	
	
	////////////////////////////////////////////////////////////////////////
	///
	///	FWK Ajax Form
	///
	////////////////////////////////////////////////////////////////////////
	var FWK_AjaxForm = function ( tObject )
	{
		/// Check to see if an object was supplied,
		/// if not, use the string to get the object
		if ( isString ( tObject ) ) {
			tObject = getItem( tObject );
		}
		
		// get the interface stuffs
		this.form   = getItem ( tObject.id + "_form" );
		this.button = getItem ( tObject.id + "_button" );
		
		this.ajax   = new FWK_Ajax    (   this );
		this.loader = new FWK_Loading ( tObject );
		
		/// assign the button action
		this.button.parent  = this;
		this.button.onclick = this.processForm;
	};
	
	FWK_AjaxForm.prototype.onAjaxTrigger  = function () { this.loader.start (); };
	FWK_AjaxForm.prototype.onAjaxResponse = function ( tResponse )
	{
		alert ( tResponse );
		this.loader.stop ();
	};
	FWK_AjaxForm.prototype.onAjaxError = function ( tResponse )
	{
		if ( tResponse == "400" )
		{
			tResponse = "There was an error with your request, please try again or contact the tech team.";
		}
		
		alert ( tResponse );
		this.loader.stop ();
	};
	
	FWK_AjaxForm.prototype.processForm = function ( )
	{
		var tParams = new Array ();
		var tID     = -1;
		
		for ( var element in this.form.elements )
		{
			if ( this.form.elements[element].nodeName )
			{
				if ( String ( this.form.elements[element].name ).indexOf ( "[" ) > -1 )
				{
					if ( String ( this.form.elements[element].type ).toLowerCase() == "checkbox" )
					{
						if ( this.form.elements[element].checked )
						{
							tParams [ tID ++ ] = Array ( this.form.elements[element].name, "true" )
						}
						else
						{
							tParams [ tID ++ ] = Array ( this.form.elements[element].name, "false" )
						}
					}
					else
					{
						tParams [ tID ++ ] = Array ( this.form.elements[element].name, this.form.elements[element].value )
					}
				}
			}
		}
		
		this.parent.ajax.makeRequest ( "/services/gateway/", tParams );
	}
	
	
	
	////////////////////////////////////////////////////////////////
	///
	///	FWK Loading
	///
	/// -----------------------------------------------------------
	///	Used to create a loading/progress bar for user interaction.
	/// In this case, the object supplied to FWK_Loading is what we
	/// want the feedback to occur above.
	///
	////////////////////////////////////////////////////////////////
	var FWK_Loading = function ( tObject )
	{
		/// Check to see if an object was supplied,
		/// if not, use the string to get the object
		if ( isString ( tObject ) ) {
			tObject = getItem( tObject );
		}
		
		/// setup all the objects
		this.me    = tObject;
		this.timer = new FWK_Timer ( 1.5, this );
		
		this.fadeValue = 0.95;
		
		/// setup the interface
		tDisplay = newElement( "div" );
		tDisplay.className = "FWK_Loading_Area";
		
		tDisplay.innerHTML ="&nbsp;";
		
		this.display = this.me.appendChild ( tDisplay );
	}

	/// creates and displays the loader
	FWK_Loading.prototype.start = function ()
	{
		/// set the classes and what not
		this.display.className     = "FWK_Loading_Area inProgress";
		//this.display.innerHTML     = "&nbsp;";
		
		/// set the transparency
		this.display.style.opacity = this.fadeValue;
		this.display.style.filter  = "alpha(opacity=" + ( Number(this.display.style.opacity) * 100 ) + ");"
		
		/// set the position
		this.updatePosition();
	}

	/// creates and displays the loader
	FWK_Loading.prototype.updatePosition = function ()
	{
		/// position the loader above this.me
		var tPosition = FWK_Position ( this.me );
		
		this.display.style.top    = tPosition.top    + "px";
		this.display.style.left   = tPosition.left   + "px";
		this.display.style.width  = tPosition.width  + "px";
		this.display.style.height = tPosition.height + "px";
	}

	/// stops and hides the loader
	FWK_Loading.prototype.stop = function ( tMessage )
	{
		this.display.className     = "FWK_Loading_Area isComplete";
		//this.display.innerHTML     = ( tMessage ) ? tMessage : "Complete";
		
		/// set the transparency
		this.display.style.opacity = this.fadeValue;
		this.display.style.filter  = "alpha(opacity=" + ( Number(this.display.style.opacity) * 100 ) + ");"
		
		this.timer.start();
	}
	
	/// Various callbacks required for the timer object
	FWK_Loading.prototype.onTimerStart = function (){};
	
	/// fades the loader out over time
	FWK_Loading.prototype.onTimerFrame  = function ( tPercent, tDuration, tEase )
	{
		/// set the transparency
		this.display.style.opacity = Math.min( ( ( ( tEase - 1 ) * -1 ) * 7 ), this.fadeValue );
		this.display.style.filter  = "alpha(opacity=" + ( Number(this.display.style.opacity) * 100 ) + ");"
	};
	
	/// Eliminates the loader once the timer has completed
	FWK_Loading.prototype.onTimerComplete = function ()
	{
		this.display.className = "FWK_Loading_Area";
		this.display.innerHTML = "&nbsp;";
		this.timer.reset();
	};
	
	
	
	
	////////////////////////////////////////////////////////////////
	///
	///	FWK Form Manager
	///
	/// -----------------------------------------------------------
	///	Used to further advance the usability of the forms in our
	/// sites.
	///
	/// Takes in all the form blocks on a page, and allows each of
	/// them to have three states:
	/// - blurred : the form elements have been filled, or the item
	///             is blurred
	/// - active  : the form block has focus
	/// - issue   : the form block has an issue
	///             [ aka failed validation ]
	///
	/// When a blocks content has focus, the blocks status [ class ]
	/// is changed to "active" and all other blocks are changed to
	/// "blurred". When the user submits the form, and validation is
	/// run, upon a failure the blocks status will be changed to issue
	/// and a messages displayed.
	///
	////////////////////////////////////////////////////////////////
	var FWK_FormManager = function ( )
	{
		this.blocks = new Array();
	}

	FWK_FormManager.prototype.registerBlock = function ( tObject )
	{
		/// Check to see if an object was supplied,
		/// if not, use the string to get the object
		if ( isString ( tObject ) ) {
			tObject = getItem( tObject );
		}
		
		/// get the blocks id
		var tCount = this.blocks.length;
		tObject.blockID = tCount;
		
		/// add the block to the registry
		this.blocks[ tCount ] = new Array();
		this.blocks[ tCount ][  'object' ] = tObject;
		this.blocks[ tCount ][   'class' ] = tObject.className + " ";
		
		/// set the class and what not
		this.blocks[ tCount ]['object'].blockID = tCount;
		this.blocks[ tCount ]['object'].originalClassName = this.blocks[ tCount ][ 'class' ];
		this.blocks[ tCount ]['object'].messageList = getClassNamedItemWithin ( "messages", getClassNamedItemWithin ( "messageArea", tObject ) );
		this.blocks[ tCount ]['object'].manager     = this;
		
		/// copy the functions to the block
		this.blocks[ tCount ]['object'].changeStatus  = this.changeStatus;
		this.blocks[ tCount ]['object'].hasIssue      = this.hasIssue;
		this.blocks[ tCount ]['object'].showMessage   = this.showMessage;
		this.blocks[ tCount ]['object'].clearMessages = this.clearMessages;
		
		/// toggle the blocks status to blurred
		this.blocks[ tCount ]['object'].changeStatus ( "blurred" );
		
		/// register a click area for the block
		this.blocks[ tCount ][  'object' ].onclick = this.selectBlock;
		
		/// cycle the blocks children and register their focus and blur actions
		var tElements = getFormElements( this.blocks[ tCount ]['object'] );  
		for ( var i = 0; i < tElements.length; i ++ )
		{
			/// set the parent
			tElements[ i ].parentID = tCount;
			tElements[ i ].block    = this.blocks[ tCount ]['object'];
			tElements[ i ].manager  = this;
			
			/// set the functions
			tElements[ i ].onfocus = this.selectBlock;
		}
		
	}
	
	/// turns all blocks off, then activates the focused block
	/// ones with issues are ignored from this process
	FWK_FormManager.prototype.activateBlock = function ( tCount )
	{
		for ( var i = 0; i < this.blocks.length; i ++ )
		{
			if ( !this.blocks[ i ]['object'].hasIssue() )
			{
				this.blocks[ i ]['object'].changeStatus ( "blurred" );
			}
		}
		
		if ( !this.blocks[ tCount ]['object'].hasIssue() )
		{
			this.blocks[ tCount ]['object'].changeStatus ( "active" );
		}
	}
	
	/// Copied onto the actual form block, so that theres
	/// a simple one call way of changing the status
	FWK_FormManager.prototype.changeStatus = function ( tStatus )
	{
		if ( tStatus == "blurred" || tStatus == "active" || tStatus == "issue" )
		{
			this.className = this.originalClassName + tStatus;
		}
		/*remove*/ else
		/*remove*/ {
		/*remove*/ 	alert ( "ERROR: the status supplied is not valid" )	;
		/*remove*/ }
	}
	
	/// Copied onto the actual form block
	/// returns a boolean value wether the block has an issue or not
	FWK_FormManager.prototype.hasIssue = function ( )
	{
		return ( this.className.indexOf ( "issue" ) < 0 ) ? false : true;
	}
	
	/// Copied onto the form blocks form elements,
	/// called when they have been given focus
	FWK_FormManager.prototype.selectBlock = function ( )
	{
		if ( this.parentID != null )
		{
			this.manager.activateBlock ( this.parentID );
		}
		else
		{
			this.manager.activateBlock ( this.blockID );
		}
	}
	
	/// Copied onto the form blocks form elements,
	/// used to replace the current notification system
	FWK_FormManager.prototype.showMessage = function ( tMessage )
	{
		/// create a new list item
		var tItem = newElement( "li" );
		tItem.innerHTML = tMessage;
		
		/// add it to the list
		this.messageList.appendChild ( tItem );
		
		/// make it glow
		this.changeStatus ( "issue" );
	}
	
	/// Copied onto the form blocks form elements,
	/// used to replace the current notification system
	FWK_FormManager.prototype.clearMessages = function ( )
	{
		/// empty the list
		this.messageList.innerHTML = "";
		
		/// stop it from glowing
		this.changeStatus ( "blurred" );
	}
	
	/// Cycles through all the blocks and resets the messages
	FWK_FormManager.prototype.resetMessages = function ( )
	{
		for ( var i = 0; i < this.blocks.length; i ++ )
		{
			this.blocks[ i ][ 'object' ].clearMessages()
		}
	}
	
	
	
	
	///////////////////////////////////////////////////////////////////////////////////////
	///
	///	FWK Stack
	///
	/// -----------------------------------------------------------------------------------
	/// A Basic object that allows for stacked service requests to be made with a simple
	/// process
	///
	///////////////////////////////////////////////////////////////////////////////////////
	var FWK_Stack = function ()
	{
		this.stackArray = new Array ();
	};
	
	FWK_Stack.prototype.addToStack = function ( tType, tName, tParam )
	{
		this.stackArray.push ( Array ( "[" + tType + "][" + tName + "]", tParam ) );
	}
	
	FWK_Stack.prototype.getStackWithId = function ( tId )
	{
		var tArray = new Array ();
		
		for ( var i = 0; i < this.stackArray.length; i ++ )
		{
			try
			{
				tArray.push ( Array ( "stack[" + tId + "]" + this.stackArray[i][0], this.stackArray[i][1] ) );
			}catch(e) {};
		}
		
		return tArray;
	}
	
	
	
	
	///////////////////////////////////////////////////////////////////////////////////////
	///
	///	FWK Expression Protocol
	///
	/// -----------------------------------------------------------------------------------
	/// Expressions are writen to assist integration between the user and the servers.
	///
	///////////////////////////////////////////////////////////////////////////////////////
	var FWK_Expression = function ( tObject )
	{
		/// check to see if what we've been supplied with is an object
		if ( isString ( tObject ) )
		{
			tObject = getItem ( tObject );
		}
		
		this.me     = tObject;
		this.loader = null;
		this.ajax   = new FWK_Ajax ( this );
		
		this.createLoader ();
	}

	FWK_Expression.prototype.makeRequest = function ( )
	{
		/// did the expression give you enough information
		if ( arguments.length > 1 )
		{
			/// check to see if ajax is processing
			if ( !this.ajax.isProcessing )
			{
				/// set the action type
				this.ajax.action = arguments [ 0 ];
				var tArray = new Array ();
				
				for ( var i = 1; i < arguments.length; i ++ )
				{
					tArray = tArray.concat ( arguments [ i ].getStackWithId ( i - 1 ) );
				}
				
				this.ajax.makeRequest ( document.serviceURL, tArray );	
			}
			else
			{
				alert ( "There is another request in progress, please wait a moment and try again." )
			}
		}
		else
		{
			alert ( "The Expression call does not have enough data to continue" )
		}
	}

	FWK_Expression.prototype.addParamsToStack = function ( tStack )
	{
		tStack.addToStack ( "service",     "module",      "Expressions" );
		tStack.addToStack (  "params",    "tagType",    this.getType() );
		tStack.addToStack (  "params", "objectType",   this.objectType );
		tStack.addToStack (    "user",      "token", document.userToken );
	}
	

	////////////////////////////////////////////////////////////////
	/// REQUIRED CONFORMITY
	FWK_Expression.prototype.add = function ( tExpression )
	{ alert ( "PROTOCOL NOT CONFORMED" ); };

	FWK_Expression.prototype.remove = function ( tExpressionID )
	{ alert ( "PROTOCOL NOT CONFORMED" ); };

	FWK_Expression.prototype.retrieve = function ( tFormat )
	{ alert ( "PROTOCOL NOT CONFORMED" ); };


	///////////////////////////////////////////////////////////////
	/// AJAX CALLBACKS
	FWK_Expression.prototype.onAjaxTrigger = function ( )
	{
		this.startLoading ( );
	};
	FWK_Expression.prototype.onAjaxResponse = function ( tData )
	{
		/// accept the successfull transaction
		this.onSuccess ( tData, this.ajax.action );
	};
	
	FWK_Expression.prototype.onAjaxError = function ( tData )
	{
		/// accept the error transaction
		this.onError ( tData, this.ajax.action );
	};


	///////////////////////////////////////////////////////////////
	/// EXPRESSION CALLBACKS
	FWK_Expression.prototype.onError = function ( tError, tAction )
	{
		this.stopLoading ( "" );
	}

	FWK_Expression.prototype.onSuccess = function ( tData, tAction )
	{
		this.stopLoading ( "" );
	}


	///////////////////////////////////////////////////////////////
	/// LOADER CALLS
	FWK_Expression.prototype.createLoader = function ()
	{		
		this.loader = new FWK_Loading ( this.me );
	}

	FWK_Expression.prototype.startLoading = function ()
	{
		this.loader.start ();
	}
	
	FWK_Expression.prototype.stopLoading = function ( tMessage )
	{
		if ( tMessage == "" )
		{
			tMessage = "Complete";
		}
		
		this.loader.stop ( tMessage );
	}
	
	
	
	
	///////////////////////////////////////////////////////////////////////////////////////
	///
	///	Global Remove Expression
	///
	///////////////////////////////////////////////////////////////////////////////////////

	var EXP_Remove = function ( tObject )
	{
		EXP_Remove.baseConstructor.call ( this, tObject );
		this.type = "";
	}
	
	FWK_Extend ( EXP_Remove, FWK_Expression );
	
	EXP_Remove.prototype.remove = function ( tKey, tType )
	{
		this.type = tType;
		
		/// Remove Stack
		var stackRemove = new FWK_Stack ();
		this.addParamsToStack ( stackRemove );
		stackRemove.addToStack ( "service",   "action",     "RemoveTag" );
		stackRemove.addToStack ( "service",   "format",         "JSON" );
		stackRemove.addToStack (  "params",     "unId",           tKey );
		stackRemove.addToStack (  "params", "objectId", this.objectId );
		
		this.makeRequest ( "remove", stackRemove );
	}
	
	EXP_Remove.prototype.getType = function ( )
	{
		return this.type;
	}
	
	EXP_Remove.prototype.onError = function ( tError, tAction )
	{
		window.location.reload()
	}

	EXP_Remove.prototype.onSuccess = function ( tData, tAction )
	{
		window.location.reload()
	}
	
	
	
	
	///////////////////////////////////////////////////////////////////////////////////////
	///
	///	Global Police Report Expression
	///
	///////////////////////////////////////////////////////////////////////////////////////
	var EXP_PoliceReport = function ( tObject )
	{
		EXP_PoliceReport.baseConstructor.call ( this, tObject );
		this.type = "";
	}
	
	FWK_Extend ( EXP_PoliceReport, FWK_Expression );
	
	EXP_PoliceReport.prototype.remove = function ( tKey, tType )
	{
		this.type = tType;
		this.objectId   = document.jsItemID;
		this.objectType = document.jsItemType;
		
		var tMessage = prompt ( "Are you sure you want to report this item?, if you're unclear on what is and isn't allowed in our Community, we suggest you visit the Community Guidelines.\n If you wish to continue with your report, please give us a reason.", 'Your Reason' );
		
		if ( tMessage != null )
		{
			/// Remove Stack
			var stackRemove = new FWK_Stack ();
			this.addParamsToStack ( stackRemove );
			stackRemove.addToStack ( "service",   "action", "addPoliceReport" );
			stackRemove.addToStack ( "service",   "format", "JSON" );
			stackRemove.addToStack (  "params",     "unId", tKey );
			stackRemove.addToStack (  "params", "objectId", this.objectId );
			stackRemove.addToStack (  "params",   "reason", tMessage );
			
			this.makeRequest ( "remove", stackRemove );
		}
	}
	
	EXP_PoliceReport.prototype.getType = function ( )
	{
		return this.type;
	}
	
	EXP_PoliceReport.prototype.onError   = function ( tError, tAction ) { this.stopLoading(); }
	EXP_PoliceReport.prototype.onSuccess = function ( tData, tAction  ) { this.stopLoading(); alert( "Your report has been submitted, a moderator will look into the report as soon as possible." ); }
	
	
