function historyChange(newLocation, historyData)

{

	if(historyData) 

	{

		document.backcnt--;

		historyData=historyData.split('|');

		sa(historyData[0], historyData[1],false);

	}

	else {window.location.hash='';window.location.reload(false);}

}

//////////////////////////////////////////////////////





function sa(urlOrForm, obj_id, bSaveBack)
{
    //if (!document.backcnt) 
	//document.backcnt=0;
	var sal = new salajax();
	sal.Debug = 0;	
    sal.PresendHtml = null;

    sal.OnError = '';

    sal.ErrorHtml == null;

	sal.EvalScripts = true;

	if(typeof (obj_id)== 'function')

		{

		sal.PassAjaxResponseToFunction(urlOrForm, obj_id);

		}

    else

	{

		/*if(obj_id=='canvas' && (bSaveBack==null || bSaveBack==true))

		{

			window.dhtmlHistory.add(document.backcnt++,urlOrForm+'|'+obj_id);

		}*/

		

		sal.SetInnerHTMLFromAjaxResponse(urlOrForm, obj_id);

	}

}

/////////////////////////////////

document.sa=sa;

if (!document.backcnt) 

	document.backcnt=0;

/////////////////////////////////////////////////////

function alert_error(v){

	if(v.length>2) alert(v);

}



function hide_loader(){

	var ajxload= document.getElementById("ajax_loader");

	if (ajxload!=null) {

		ajxload.style.display='none';

	}

	

}

function show_loader()

{

	var ajxload= document.getElementById("ajax_loader");

	if (ajxload!=null) 

	{

		ajxload.style.top=getPageSize()[3]/2-32 + getScrollXY()[1];

		ajxload.style.left=getPageSize()[2]/2-32 + getScrollXY()[0];

		ajxload.style.display='block';

	}

	

}



/*

The Salajax Class.

Ajax class that allows use of the back button and bookmarks.

Written by Nigel Liefrink.





| This software is provided "as is", without warranty of any kind, express or |

| implied, including  but not limited  to the warranties of  merchantability, |

| fitness for a particular purpose and noninfringement. In no event shall the |

| authors or  copyright  holders be  liable for any claim,  damages or  other |

| liability, whether  in an  action of  contract, tort  or otherwise, arising |

| from,  out of  or in  connection with  the software or  the  use  or  other |

| dealings in the software.   



14-05-2007 : v2.0 Initial version release.  



Usage:

    //set up the salajax settings.

    var sal = new salajax();

    sal.Debug = 0;

    sal.EnableBackButton(true); //turns on the back buttons.

    sal.EnableBookmarks(true); //saves state in the clients cookies so bookmarks will work provided they havn't deleted their cookies.

    sal.OnStart = 'TestOnStart()'; //enables a script to run before the request is made. e.g. change pointer/icon/loading section of page.

    sal.OnEnd = 'TestOnEnd()'; //enables a script to run after the request is returned. e.g. change pointer/icon/loading section of page.

    sal.PresendHtml = '<img border="0" src="http://www.ajaxload.info/cache/ff/ff/ff/00/80/ff/24-1.gif"/>';

    sal.OnError = 'DefaultOnError()';//set a function to pass to if there is an error.

    sal.OnErrorHtml = '<img border="0" src="http://www.register.com/images/icons/error_icon.gif" /><font color="red">Error!</font>'; //When calling  etInnerHTMLFromAjaxResponse and there is an error, this will be displayed.

    sal.EvalScripts = true; //if set to true, will evaluate any javascript in the responseText. 

                             //NOTE: to use functions returned in your responseText you must declare the functions in your ajax response like this:

                             //         var FunctionToChange = function(var1,var2)

                             //         { 

                             //             //do stuff

                             //         }

                             //            

    this.KeepDotNetViewState = true; //if set to true will post the current viewstate when using .NET

    //end setting the salajax settings.

    

    

    Some examples of main usage in web page:

    sal.PassAjaxResponseToFunction('/myscript.*?getsomehtml=1', 'FunctionToHandleTheResponse');

    sal.PassAjaxResponseToFunction(document.forms[0], 'FunctionToHandleTheResponse');



	sal.SetInnerHTMLFromAjaxResponse('/myscript.*?getsomehtml=1', 'id_of_div'); //using get and string of id div.

	sal.SetInnerHTMLFromAjaxResponse(document.forms[0], object);//using post and object to change the innerhtml of.

	sal.SetInnerHTMLFromAjaxResponse('form', 'id_of_div');//using post ('form' will submit forms[0]'), object to change the innerhtml of.



    Read function definitions for more detail.







*/

function salajax()

{

    this.Debug = 0;//1=Debug, 2=Verbose - will cause alert statements to popup.

    this.PresendHtml = ' Tai Loading...'; //TODO: use an image. When set to null, this will leave the current html until the response is returned.

    this.OnStart = '';//set a function to pass to eval.

    this.OnEnd = '';//set a function to pass to eval.

    this.OnError = 'DefaultOnError()';//set a function to pass if there is an error.

    this.OnErrorHtml = '<font color="red">Error!</font>'; //When setting InnerHtml and there is an error this will be displayed. Set to null to turn this feature off.

    this.EvalScripts = false; //if set to true, will evaluate any javascript in the responseText.

    this.KeepDotNetViewState = false; //if set to true will post the current viewstate when using .NET

    this.EnableBookmarkDays = 600; //how many days to keep the bookmarks..

    //TODO: Possibly save state on server, send the key in the request to the server or make a seperate ajax call to get and save state...

    //this.SaveStateOnServer = false; //if set to true will send the key name with the request.

    

    //Also Available are these two functions.

    //this.EnableBackButton(false);

    //this.EnableBookmarks(false);



    var _backButtonEnabled = false;

    var _bookmarksEnabled = false;

    var _savedstate = new Object();

    var _savedkeys = new Array();

    

    var self = this;

    

    

    //enables back button and storing of state keys in the # of the url.

    //will also start polling for any changes to the hash, so as to update the ajax section of the page.

    this.EnableBackButton = function(blnEnable) 

    {

        _backButtonEnabled = blnEnable;

        if(blnEnable)

        {

            this.PollForStateChange();

        }

    }

    

    //Default Function to call when there is an error.

    var DefaultOnError = function()

    {

        alert('There was an error loading the data. Sorry for the inconvenience.');

    }
    /**
    <summary>
    Gets the response stream from the passed url, and then calls the callbackFuntion passing the response and the div_ids.
    </summary>
    <param name="url">The url to make the request to get the response data.</param>
    <param name="callbackFunction">The function to call after the response has been recieved. the response <b>must</b> always be the first argument to the function.</param>
    </summary>
    <example>
	<code>
	var sal = new salajax();
	sal.PassAjaxResponseToFunction('?getsomehtml=1', 'FunctionToHandleTheResponse');
    function FunctionToHandleTheResponse(response){

	    var data = response.split(';');

	    document.getElementById('d1').innerHTML = data[0];

	    document.getElementById('d2').innerHTML = data[1];

	    document.getElementById('d3').innerHTML = data[2];

    }

	    </code>

    </example>

    */

    this.PassAjaxResponseToFunction = function (urlOrForm, callbackFunction)

    {		

      if(this.onStart != '')

      {

        eval(this.OnStart);

      }

      var xmlhttp = new this.GetXmlHttp();

      //now we got the XmlHttpRequest object, send the request.

      if(this.Debug >= 2)

      {

        alert(urlOrForm);

      }



      if (xmlhttp)

      {

         xmlhttp = this.SetReadyStateForFunction(xmlhttp, callbackFunction)                          

         this.SubmitXmlHttp(urlOrForm, xmlhttp, 'f|'+callbackFunction);

      }



    }





    /**

    ///<summary>

    ///Sets the innerHTML property of obj_id with the response from the passed url or form./

    ///</summary>

    ///<param name="urlOrForm">The url or form to submit to make the request to get the response data.</param>

    ///<param name="obj_id">The object or the id as a string of the object to set the innerHTML for.</param>

    <example>

	<code>

	var sal = new salajax();

	sal.SetInnerHTMLFromAjaxResponse('?getsomehtml=1', 'id_of_div'); //using get and string of id div.

	sal.SetInnerHTMLFromAjaxResponse(document.forms[0], object);//using post and object to change the innerhtml of.

	sal.SetInnerHTMLFromAjaxResponse('form', object);//using post ('form' will submit forms[0]'), object to change the innerhtml of.

	</code>

    </example>

    */

    this.SetInnerHTMLFromAjaxResponse = function (urlOrForm, obj_id)

    {	

		show_loader();

      if(this.onStart != '')	                                                    {

        eval(this.OnStart);

      }

	  

      

      var xmlhttp = new this.GetXmlHttp();

      //now we got the XmlHttpRequest object, send the request.

      if (xmlhttp)

      { 

        if(typeof obj_id == 'string')

        {

           obj_id = document.getElementById(obj_id);

        }

        

        xmlhttp = this.SetReadyStateForInnerHtml(xmlhttp, obj_id)

       

        if(this.PresendHtml != null)

        {

            obj_id.innerHTML = this.PresendHtml;

        }

		

        var bb_div_id = obj_id.id;

	    this.SubmitXmlHttp(urlOrForm, xmlhttp, 'h|'+bb_div_id);



      }

    }

    



    /**

    Browser Compatability function.

    Returns the correct XMLHttpRequest depending on the current browser.

    */

    this.GetXmlHttp = function() {	

                var xmlhttp = false;

                if (window.XMLHttpRequest)

                {

                    xmlhttp = new XMLHttpRequest();

                }

                else if (window.ActiveXObject)// code for IE

                {

                    try 

                    {

	                    xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");

                    } 

                    catch (e) 

                    {

	                    try 

	                    {

		                    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

	                    } catch (E) {

		                    xmlhttp=false;

	                    }

                    }

                }

                return xmlhttp;

            }



    /**

        Returns the values of the form as a Post string to add to the header of the request.

        Modified from code here: http://www.codeproject.com/Ajax/AJAXWasHere-Part1.asp

    */

    this.GetPostDataFromForm = function(theform)

    {

        var theData = '';

        var eName = '';



        if(this.Debug >= 1)

        {

			alert('Form:'+theform.name + 'fields:'+theform.elements.length);

        }

    	

        theData = 'ajax=true&';

        for( var i=0; i<theform.elements.length; i++ )

        {

            eName = theform.elements[i].name;

            if(eName == '')

            {

                eName = theform.elements[i].id;

            }



            if(this.Debug >= 2)

            {

                alert('FormElement:'+eName+'='+theform.elements[i]);

            }



            //Handle .NET VIEWSTATE

            if( eName && eName != '')

            {

              

              if(  eName == '__EVENTTARGET' 

                || eName == '__EVENTARGUMENT' 

                || eName == '__VIEWSTATE' )

              {

                if(eName = '__VIEWSTATE' && this.KeepDotNetViewState)

                {

                    theData += '__VIEWSTATE=' + escape(theform.__VIEWSTATE.value).replace(new RegExp('\\+', 'g'), '%2b') + '&';

                }

              }

              else

              {

				//check if field is a checkbox

				if(theform.elements[i].type=="checkbox"){

					var cv="0";

					if(theform.elements[i].checked) cv="1";

					theData = theData + escape(eName) + '=' + encodeURIComponent(cv);

				}

				else if(theform.elements[i].type == "radio"){

					if (theform.elements[i].checked) theData = theData + escape(eName) + '=' + encodeURIComponent(theform.elements[i].value);

				}

				else if(theform.elements[i].type == "select-one"){

					theData = theData + escape(eName) + '=' + encodeURIComponent(theform.elements[i].options[theform.elements[i].selectedIndex].value);

				}

                else theData = theData + escape(eName) + '=' + encodeURIComponent(theform.elements[i].value);

                if( i != theform.elements.length - 1 )

                  theData = theData + '&';

              }

            }

            }//end for

            if(this.Debug >= 1)

            {

                alert('DataToSend:'+theData);

            }

        return theData;

        }





        /**

            Sets up the xmlhttp object to pass the responseText to a the specified callbackfunction.

            Private method.

        */

        this.SetReadyStateForFunction = function (xmlhttp, callbackFunction)

        {

            var debug = this.Debug;

            var onEnd = this.OnEnd;

            var onError = this.OnError;

            

             xmlhttp.onreadystatechange = function () 

                                            {

                                                if (xmlhttp && xmlhttp.readyState==4)

                                                {//we got something back..

                                                    if (xmlhttp.status==200)

                                                    {

	                                                    var response = xmlhttp.responseText;

	                                                    var functionToCall = callbackFunction+'(response)';

	                                                    if(debug >= 2)

														{

		                                                    alert(response);

		                                                    alert(functionToCall);

	                                                    }

	                                                    if(typeof(callbackFunction=='function')) callbackFunction(response);

														else eval(functionToCall);

    	                                                

	                                                    if(onEnd != '')

                                                        {

                                                            eval(onEnd);

                                                        }

                                                        

                                                    } 

                                                    else

                                                    {

                                                      if(onError != '')

                                                      {

                                                        eval(onError);

                                                      }

                                                      if(debug >= 1)

                                                      {

	                                                    document.write(xmlhttp.responseText);

                                                      }

                                                    }

                                                    



                                                }

                                            }

            return xmlhttp;

        }

        

         /**

            Sets up the xmlhttp object to update the innerHTML of the obj_id with the responseText.

            Private method.

        */

        this.SetReadyStateForInnerHtml = function (xmlhttp, obj_id)

        {



            var onEnd = this.OnEnd;

            var debug = this.Debug;

            var onError = this.OnError;

            var self = this;

            

                xmlhttp.onreadystatechange = function () 

                                            {

                                                if (xmlhttp && xmlhttp.readyState==4)

                                                {//we got something back..

                                                    if (xmlhttp.status==200)

                                                    {

	                                                    if(debug >= 1){

		                                                    alert(xmlhttp.responseText);

	                                                    }

		                                                obj_id.innerHTML = xmlhttp.responseText;

														hide_loader();

    	                                                

	                                                    if(self.EvalScripts)

                                                        {

                                                            self.EvaluateScripts(xmlhttp.responseText);

                                                        }

                                                        

	                                                    if(onEnd != '')

                                                        {

                                                            eval(onEnd);

                                                        }

         

                                                    } 

                                                    else

                                                    {

                                                      if(onError != '')

                                                      {

                                                        eval(onError);

                                                        obj_id.innerHTML = self.OnErrorHtml;

                                                      }

                                                      if(debug >= 1)

                                                      {

	                                                    document.write(xmlhttp.responseText);

                                                      }

                                                    }

                                                }

                                            }

            return xmlhttp;

        }



        /**

            Evaluates any javascript that is in the responseText.

            **NOTE: if you want to use functions that are in the responseText, the function must be written as a variable.

            (this can easily be achieved by swapping the name and the function declaration around and adding an '=' sign.)

            e.g.

                

                AFunctionInTheResponse = function(some, vars)

                {

                    //do stuff with some vars

                }

                NOT: function AFunctionInTheResponse(some, vars){ // this will not work. }

            Private Method.

        */            

        this.EvaluateScripts = function(responseText)

        {

			

			var rt=responseText.replace(/<textarea[.\s\S]*\/textarea>/gi,'');

            var matchAll = new RegExp('(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)', 'img');

            var scripts = '';

            while (scripts = matchAll.exec(rt))

            {

                eval(scripts[1]);

            }

        }

             

            

        /*

        Submits the initialised xmlhttp object to the server.

        and updates the address bar if back button is enabled.

        Private Method.

        */

        this.SubmitXmlHttp = function (urlOrForm, xmlhttp, callid)

        {

			

            //quick param for submitting the first form                        

            if(urlOrForm == 'form'){

                urlOrForm = document.forms[0];

            }          

            

            var bb_params;		

                                                                            

            if(typeof urlOrForm == 'string')

            { //it a get request.          

              var url = urlOrForm;

              if(url.indexOf('?') == 0)//is shortcut link

              {

                url = document.location.pathname+url;

              }

                xmlhttp.open("GET",url,true);

              	 // xmlhttp.send(theData);

			   xmlhttp.send(null);

    			

                bb_params = '|g|'+url+'|'+callid

            } 

            else 

            { //it is a form.... submit all the values

                var f = urlOrForm

                var theData = this.GetPostDataFromForm(f);

				

                if(f.action == null || f.action == "")

                {

                    f.action = document.location.pathname;

                }

                if(f.action.indexOf('?') == 0)

                {

                    f.action = document.location.pathname+f.action;

                }

                

                xmlhttp.open('POST', f.action, true);

                xmlhttp.setRequestHeader('Content-Type', 

												                    'application/x-www-form-urlencoded');

                xmlhttp.send(theData);

                bb_params = theData+'|p|'+f.action+'|'+callid

    			   

            } 

            if(_backButtonEnabled)

            {

                UpdateAddressBar(bb_params);

            }

        }

             

             

             

             



                

    /*

    Updates the address bar and adds the saved params using the hashlistenter.

    //extra vals stored as | [posttype(g=get,p=post) | url/action | f=function,h=setinnerhtml | funcname or divname

    */

    var UpdateAddressBar = function(address) {

    

        var split = address.split('|');

        //the last is the Div that was changed.

        var keyn = split[split.length-1]; //use this as the key to store the data.

        var hash = hashListener.getHash().substring(1);//remove the '#'

        var hashkeys = hash.split(':');

        var keysaved = false;

        var stateIsSavedAs = '';

        

        if(_bookmarksEnabled)

        { //check cookies to see if the state has been saved in da cookie

            var cs = document.cookie.split(';');

            for(var c=0;c<cs.length;c++)

            {

                var ckey = cs[c].substring(0,cs[c].indexOf('=')).trim()

                var ckeyn = ckey.split('@');

                ckeyn = ckeyn[0];

                var cval = cs[c].substring(cs[c].indexOf('=')+1,cs[c].length);

                //alert('cookKey'+c+':'+ckey+'\n'+'cookVal'+c+':'+cval);

                if(keyn == ckeyn && cval == address)

                {

                    var stateissaved = cs[c].split('=');

                    stateIsSavedAs = stateissaved[0].trim();

                    break;

                }

            }

        }

        

        //check in the state object

        if(stateIsSavedAs == '')

        {

            for(var i=0;i<_savedkeys.length;i++)

            {

                var skey = _savedkeys[i];

                var skeyn = skey.split('@');

                skeyn = skeyn[0];

                //alert('Checking if Saved\n'+'Key:'+_savedkeys[i]+'\n'+address + ' ==\n'+ _savedstate[_savedkeys[i]]);

                if(skeyn == keyn && address == _savedstate[skey])

                {

                    stateIsSavedAs = skey; //set to the key that has been saved.

                    break;

                }

            }

        }

        

        //work out the old key

        var oldkey = '';

        for(var i=1; i<hashkeys.length; i++)

        {

            var hashkey = hashkeys[i].split('@');

            var hashkeyn = hashkey[0];

            var hashkeye = hashkey[1];



            if(hashkeyn == keyn)//this section has been changed by an ajax request.

            {

                oldkey=hashkeys[i];

                break;

            }

        }

        

        //if the state hasn't been saved we need to create a new key.

        if(stateIsSavedAs == '')

        {

            g_eventCount++;

            key = keyn +'@'+g_eventCount;

            SaveState(key, address);

//alert('Created New Key:'+key);

        } 

        else //just save the state

        {

            key = stateIsSavedAs;

//alert('Key is saved:'+key);

            SaveState(key, address);

        }

        

        

        if(oldkey == '')

        {

            hash+=':'+key;

        } else {  

            hash = hash.replace(oldkey, key);

        }

        

        hashListener.setHash(hash);

    }      

    

    

    //Used for saving the state of an ajax request.

    var SaveState = function(key, data)

    {

        _savedstate[key] = data;

        _savedkeys.push(key);

         if(_bookmarksEnabled)

         {

            createCookie(key, data, self.EnableBookmarkDays);

         }

         //TODO:Store state information on server via ajax requests? Cookie is limited to 4K. (not much)

         //Or Maybe one of these methods http://www.niallkennedy.com/blog/archives/2007/01/ajax-performance-local-storage.html

    }

    

    //Gets the state of an ajax element.

    var GetState = function(key)

    {

        if(_bookmarksEnabled && _savedstate[key] == null)

        {

            return readCookie(key);

        } else {

            return _savedstate[key];

        }

        //TODO:Get state information from server via ajax requests?

    }

    

    

    

    //Private Function to update all the ajax elements 

    //from the keys that are contained in the hash of the url.

    var UpdateAjaxDivs = function()

    {

       //TODO: get key from the address bar 

       // return state information from a cookie

       // or on the server using the key as a reference.

        var hash = hashListener.getHash();

        hash = hash.substring(1);

        if(hash != '')

        {

            var savedkeys = hash.split(':');

            for(var i=1;i<savedkeys.length;i++)

            {

                //TODO: keep/find the last state of this div

                //So we don't make any uneeded ajax requests divs, ie already set.

                

                var data = GetState(savedkeys[i])

                if(data != null)

                {

				var data = data.split('|');

                if(data.length >= 4) 

                {

                    var funcdiv = data.pop();

                    var fh = data.pop();

                    var url = data.pop();

                    var postget = data.pop();

                    var xmlhttp = self.GetXmlHttp();

                    //now we got the XmlHttpRequest object, send the request.

                    if (xmlhttp)

                    { 

                        if(self.onStart != '')

                        {

                            eval(self.OnStart);

                        }

                    

                        if(fh == 'h')

                        {

                           var fd = document.getElementById(funcdiv);

                           if(fd == null)

                           {

                                //setTimeout(this.PollForStateChange, this.BBPoleTime);

                                return;

                           }

                           xmlhttp =  self.SetReadyStateForInnerHtml(xmlhttp, fd)

                        } else {//set for function.

                            

                           xmlhttp = self.SetReadyStateForFunction(xmlhttp, funcdiv)

                        }

                        

                        //set the inner html if we are affecting a div.

                        if(fd)

                        {

                            if(self.PresendHtml != null)

                            {

                                fd.innerHTML = self.PresendHtml;

                            }

                        }

                        

                        //send the request via ajax

                        if(postget == 'p')

                        {

                            //reconstruct theData

                            var theData = data.pop(); 

                            

                            xmlhttp.open('POST', url, true);

                            xmlhttp.setRequestHeader('Content-Type','application/x-www-form-urlencoded');



                            if(self.Debug > 0){

					            alert('TheData:'+theData);

					        }

							

                            xmlhttp.send(theData);



                        } else {//g

                            xmlhttp.open('GET',url,true);

                            xmlhttp.send(null);

                        }

                    }

                }

                }//if data.length

            } //end for

        }else{//no hash

            //document.location.reload();

        } 

    }

    

    

    //if set to true will store state information in cookies

    //on the clients computer.

    this.EnableBookmarks = function(blnEnable) 

    {

        _bookmarksEnabled = blnEnable

        if(blnEnable)

        {

            setTimeout(UpdateAjaxDivs,100);

        }

    }

    

    

    

    /*

    If the back button is enabled this method will watch for changes to the hash

    and update the ajax areas when a change is detected.

    */

    this.PollForStateChange = function()

    {

        if(_backButtonEnabled)

        {

           hashListener.onHashChanged = UpdateAjaxDivs

        } 

        else 

        {//disable back button - could potentially remove other instances that are monitoring.

         //hashListener.onHashChanged = function(){}

        }

    }      

}//END salajax_class













String.prototype.trim = function() {return this.replace(/^\s+|\s+$/g,"");}

//String.prototype.ltrim = function() {return this.replace(/^\s+/g,"");}

//String.prototype.rtrim = function() {return this.replace(/\s+$/g,"");}





/* Backward compatability. */

function PassAjaxResponseToFunction(urlOrForm, callbackFunction)

{

    var sal = new salajax();

    sal.PresendHtml = null;

    sal.OnError = '';

    sal.ErrorHtml == null;

    sal.PassAjaxResponseToFunction(urlOrForm, callbackFunction);

}



/* Backward compatability. */

function SetInnerHTMLFromAjaxResponse(urlOrForm, obj_id)

{

    var sal = new salajax();

    sal.PresendHtml = null;

    sal.OnError = '';

    sal.ErrorHtml == null;

    sal.SetInnerHTMLFromAjaxResponse(urlOrForm, obj_id);

}



/*

//This ensures that bookmarks cannot be overridden by replacing the key values saved in cookies.

//NOTE: cookies do have a limitation in size of data that can be saved..

//NOTE: ints may eventually run out and cause issues

//TODO: fix these potential problems.

*/

function GetSafeEventCount()

{

    var retVal = 0;    

    var cs = document.cookie

    cs = cs.split(';');

    for(var c=0;c<cs.length;c++)

    {

        var ckey = cs[c].substring(0,cs[c].indexOf('='))

        var ckeyn = ckey.split('@');

        if(ckeyn[1] != null && ckeyn[1] > retVal)

        {

            retVal = ckeyn[1];

        }

    }

    return parseInt(retVal);

}                      

var g_eventCount = GetSafeEventCount(); 

    















/*----------------------------------------------------------------------------\

|                             Hash Listener 1.0                               |

|-----------------------------------------------------------------------------|

|                         Created by Erik Arvidsson                           |

|                  (http://webfx.eae.net/contact.html#erik)                   |

|                      For WebFX (http://webfx.eae.net/)                      |

|-----------------------------------------------------------------------------|

|   Basic object to allow updating the hash part of the document location.    |

|-----------------------------------------------------------------------------|

|                  Copyright (c) 1998 - 2005 Erik Arvidsson                   |

|-----------------------------------------------------------------------------|

| Basic object to allow updating the hash part of the document location.      |

| Mozilla always adds an entry to the history but for IE we add an optional   |

| flag whether to add an entry to the history and if this is set an iframe is |

| used to support this behavior (this is on by default).                      |

|                                                                             |

| When the hash value changes onHashChanged is called. Override this to do    |

| your own callbacks.                                                         |

|                                                                             |

| Usage: Include script                                                       |

|        Override onHashChanged: hashListener.onHashChanged = fn              |

|                                                                             |

| Known issues: Known to not work with Opera                                  |

|               Not tested with KHTML/Safari                                  |

|               Might interfere with other iframe based loading               |

|- ---------------------------------------------------------------------------|

| This software is provided "as is", without warranty of any kind, express or |

| implied, including  but not limited  to the warranties of  merchantability, |

| fitness for a particular purpose and noninfringement. In no event shall the |

| authors or  copyright  holders be  liable for any claim,  damages or  other |

| liability, whether  in an  action of  contract, tort  or otherwise, arising |

| from,  out of  or in  connection with  the software or  the  use  or  other |

| dealings in the software.                                                   |

| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |

| ... removed standard license part of header for now...                      |

|-----------------------------------------------------------------------------|

| 2005-05-15 | First version                                                  |

|-----------------------------------------------------------------------------|

| Created 2005-05-15 | All changes are in the log above. | Updated 2005-05-15 |

\----------------------------------------------------------------------------*/

//Note that I have made some changes to this class in order to get it to work with salajax class.

var hashListener = {

	ie:		/MSIE/.test(navigator.userAgent),

	ieSupportBack:	true,

	hash:	document.location.hash,

	initialised: false,

	check:	function () {

		var h = document.location.hash

		var h2 = this.hash



		if (h != h2) {

		    //alert(h+"\n:\n"+h2)

			this.hash = h;

			this.onHashChanged();

		}

	},

	init:	function () {



		// for IE we need the iframe state trick

		if (this.ie && this.ieSupportBack) {

			var frame = document.createElement("iframe");

			frame.id = "state-frame";

			frame.style.display = "none";

			document.body.appendChild(frame);

			this.writeFrame("");

		}



		var self = this;



		// IE

		if ("onpropertychange" in document && "attachEvent" in document) {

			document.attachEvent("onpropertychange", function () {

				if (event.propertyName == "location") {

					self.check();

				}

			});

		} else {

		// poll for changes of the hash

		    window.setInterval(function () { self.check() }, 100);

		}

		this.initialised = true;

	},

	setHash: function (s) 

	{

	    this.hash = '#'+s;

		// Mozilla always adds an entry to the history

		//this.init();

		

		if(!this.initialised)

		{

		    this.init();

		}

		

		if (this.ie && this.ieSupportBack) {

			this.writeFrame(s);

		}

		//if (this.hash != '' && this.hash != document.location.hash) {

			document.location.hash = this.hash;

		//}

	},

	getHash: function () 

	{

		return document.location.hash;

	},

	writeFrame:	function (s) 

	{

		var f = document.getElementById("state-frame");

		var d = f.contentDocument || f.contentWindow.document;

		d.open();

		d.write("<script>window._hash = '" + s + "'; window.onload = parent.hashListener.syncHash;<\/script>");

		d.close();

	},

	syncHash:	function () 

	{

		var s = this._hash;

		if (s != '' && s != document.location.hash)

		{

		document.location.hash = s;

		}

	},

	onHashChanged:	function () {}

};





function createCookie(name, value, days) {

	if (days) 

	{

		var date = new Date();

		date.setTime(date.getTime()+(days*24*60*60*1000));

		var expires = "; expires="+date.toGMTString();

	}

	else 

	var expires = "";

	document.cookie = name+"="+value+expires+"; path=/";

}

////////////////////////////////////////

function createCookieSec(name, value, seconds) 

{

	if (seconds) 

	{

		var date = new Date();

		date.setTime(date.getTime()+(seconds*1000));

		var expires = "; expires="+date.toGMTString();

	}

	else 

	var expires = "";

	document.cookie = name+"="+value+expires+"; path=/";

}



/////////////////////////////////

function readCookie(name) {

	var nameEQ = name + "=";

	var ca = document.cookie.split(';');

	for(var i=0;i < ca.length;i++) {

		var c = ca[i];

		while (c.charAt(0)==' ') c = c.substring(1,c.length);

		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);

	}

	return null;

}



/////////////

function eraseCookie(name) 

{

	createCookie(name,"",-1);

}



