var requiredVersion = 4;
var useRedirect = true;
var flashPage = "";
var noFlashPage ="";
var pageURL = "";
var flash2Installed = false;
var flash3Installed = false;
var flash4Installed = false;
var flash5Installed = false;
var flash6Installed = false;
var flash7Installed = false;
var flash8Installed = false;
var flash9Installed = false;
var flash10Installed = false;
var flash11Installed = false;
var flash12Installed = false;
var maxVersion = 12;
var actualVersion = 0;
var hasRightVersion = false;
var transparentFlash="false";
var jsVersion = 1.0;
var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false;
var isWin = (navigator.appVersion.indexOf("Windows") != -1) ? true : false;
jsVersion = 1.1;

// Use VBScript written to the browser if this is IE on Windoze
if(isIE && isWin){
  document.write('<SCR' + 'IPT LANGUAGE=VBScript\> \n');
  document.write('on error resume next \n');
  document.write('flash2Installed = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.2"))) \n');
  document.write('flash3Installed = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.3"))) \n');
  document.write('flash4Installed = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.4"))) \n');
  document.write('flash5Installed = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.5"))) \n');  
  document.write('flash6Installed = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.6"))) \n');  
  document.write('flash7Installed = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.7"))) \n');  
  document.write('flash8Installed = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.8"))) \n');  
  document.write('flash9Installed = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.9"))) \n');  
  document.write('flash10Installed = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.10"))) \n');  
  document.write('flash11Installed = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.11"))) \n');  
  document.write('flash12Installed = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.12"))) \n');  
  document.write('</SCR' + 'IPT\> \n'); // break up end tag so it doesn't end our script
}

detectFlash();

function firing()
{
try
{
firesliders();
}
catch(err)
{
}
}


function urchinTracker(s)
{
pageTracker._trackPageview(s);
}

function detectFlash() 
{  

		if (navigator.plugins) 
		{
			if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) 
			{
				var isVersion2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : "";
				var flashDescription = navigator.plugins["Shockwave Flash" + isVersion2].description;
				var pieces;
				pieces = flashDescription.split(" ")
				var flashVersion = pieces[2];
				splitnum = flashVersion.split(".");
				flashVersion = splitnum[0];
				//var flashVersion = parseInt(flashDescription.charAt(flashDescription.indexOf(".") - 1));
				flash2Installed = flashVersion == 2;    
				flash3Installed = flashVersion == 3;
				flash4Installed = flashVersion == 4;
				flash5Installed = flashVersion == 5;
				flash6Installed = flashVersion >= 6;
				flash7Installed = flashVersion >= 7;
				flash8Installed = flashVersion >= 8;
				flash9Installed = flashVersion >= 9;
				flash10Installed = flashVersion >= 10;
				flash11Installed = flashVersion >= 11;
				flash12Installed = flashVersion >= 12;
			}
		}

		// Set Maximum Version installed
		for (var i = 2; i <= maxVersion; i++) if (eval("flash" + i + "Installed") == true) actualVersion = i;
		// WebTV kludge
		if(navigator.userAgent.indexOf("WebTV") != -1) actualVersion = 3;  
		

} // end detectFlash


function ProductPageForward(strState)
{
	var curQS = DP_QueryString.getAll();
	strURL = new String(document.location)
	curQS.State=strState;
	document.location.href = strURL.split("?",1)+DP_QueryString.generate(curQS);
}



var DOM_OBJECTS = Array();
var nav_off_regex = /(\.+)[0](\.gif)$/;


function initNavMouseovers(nav_id) {

	if (DOM_OBJECTS[nav_id] = document.getElementById(nav_id)) {

		var nav_images = Array();
		nav_images = DOM_OBJECTS[nav_id].getElementsByTagName('img');

		for (var i=0; i< nav_images.length; i++) {
			if (!nav_off_regex.test(nav_images[i].src)) continue;

			nav_images[i].std_img = new Image();
			nav_images[i].std_img.src = nav_images[i].src;

			nav_images[i].hover_img = new Image();
			nav_images[i].hover_img.src = nav_images[i].src.replace(nav_off_regex, "$1" + "1" + "$2");

			nav_images[i].onmouseover = function() { this.src = this.hover_img.src; };
			nav_images[i].onmouseout = function() { this.src = this.std_img.src; };

		}


	}

} // end initNavMouseovers()


function echo(sString)
{
document.write(sString);
}


function echoToElement(sElement,sString)
{
document.getElementById(sElement).innerHTML=sString;
}


function TableToggle(WhichSection) {
	var CurrSection = document.getElementById(WhichSection);
	if ((CurrSection.className == "showtablecolumn") || (CurrSection.className.length == 0)) {
		CurrSection.className = "hidetablecolumn";
	} else {
		CurrSection.className = "showtablecolumn";
	}
}

function TableToggleOff(WhichSection) {
	var CurrSection = document.getElementById(WhichSection);
		CurrSection.className = "hidetablecolumn";
}


function HomeFinderStep2Submit(Search_Type) {

	s.events='event18';
	s.linkTrackVars='events';
	s.linkTrackEvents='event18';
	s.tl(this,'o','HomeFinder');

	// Search_Type == "homes" || "communities"
	var f = document.forms['home_finder_step_2'];
	var region = f.elements['Region'].value;
	var area = f.elements['Area'].value;
	if ((f.elements['Region'].value == 'Select a Region') || (f.elements['Region'].value == '')){
		alert('Please select a region from the list.');
		return false;}
	if (region.slice(0,1) == '*')
	{
		//alert('Offsite region.');
		return false;
	}
	f.elements['Search_Type'].value = Search_Type;
	f.elements['State'].value=f.elements['stateselected'].value;
	f.submit();
	return true;
}
 
var pEl ;
var bColor;
var pSelType;
var pDelType;
var pSelDisMeth;
var pContBtn;

function ActivateRow(backColor,nRow)
{  
	// Turn off the previously selected elements - if they exist//
	if(typeof(pEl)!='undefined') 
	{
	pEl.bgColor=bColor; 
	} 

	if(typeof(pSelType)!='undefined') 
	{
	pSelType.disabled=true;
	} 

	if(typeof(pDelType)!='undefined') 
	{
	pDelType.disabled=true;
	} 

	if(typeof(pContBtn)!='undefined') 
	{
	pContBtn.disabled=true
	} 

	 //change the color of the row//
	 var el = event.srcElement;
	 el = el.parentElement.parentElement;
	 bColor = el.bgColor;
	 el.bgColor=backColor;
	 pEl = el; 
	 
/*	for some reason, the form reset is not returning the form to the original state on the page load
	 //reset the form //
	 var eLForm = document.getElementById('TypeForm');
	 alert('form ['+typeof(eLForm)+']')
	 if(typeof(eLForm)!='undefined') 
		{
		alert('not undef')
		eLForm.reset(); 
		} 
*/
	// Enable this row's type select element //
	if(typeof(document.getElementById('TypeSelect'+nRow))!='undefined') 
		{
		 document.getElementById('TypeSelect'+nRow).disabled=false;
		} 

	// Enable this row's type select element //
	if(typeof(document.getElementById('Delete'+nRow))!='undefined') 
		{
		try
			{
			 document.getElementById('Delete'+nRow).disabled=false;
			}
		 catch(err)
			{
//alert('could not enable delete button')
			}
		} 
	 
	 // enable this rows Continue button //
	if(typeof(document.getElementById('Continue'+nRow))!='undefined') 
		{
		document.getElementById('Continue'+nRow).disabled=false;
		} 
	 
	 // Remember the current ones so we can turn them off if the user goes to another row//
	 pSelType = document.getElementById('TypeSelect'+nRow);
	 pDelType = document.getElementById('Delete'+nRow);
	 pContBtn = document.getElementById('Continue'+nRow);
	 
 //enable the item checkboxes//
 for (i=1;true;i++)
	{
	var oElement = document.getElementById('DeleteItem-'+nRow+'-'+i);
	if(typeof(oElement)!='undefined') 
		{	
		try
			{
				if (oElement.getAttribute('value')=='End')
					{
					// break out of loop
					break;
					}
				oElement.disabled=false
			}
			catch(err)
			{
//alert('cannot disable ' + i);
			}
		} 
	}
}

function myErrorHandler()
{
alert('error')
}

onload_events = new Array();
onload_events[onload_events.length] = "initNavMouseovers('MainNav')";
onload_events[onload_events.length] = "initNavMouseovers('AuxNav')";
onload_events[onload_events.length] = "initNavMouseovers('AlienNavWrapper')";
onload_events[onload_events.length] = "try{firing()}catch(err){}";

window.onload = function(){
	for (var i=0; i< onload_events.length; i++) {
		eval(onload_events[i]);
	}
};


// TriggerManualOnload... To trigger scenarios where other manual events are needed to be placed outside of this file...
//If you add something somewhere else in the BODY tag, it will break the window.onload definition here.
function TriggerManualOnLoad()
{
	for (var i=0; i< onload_events.length; i++) {
		eval(onload_events[i]);
	}
}


function ToggleMusic(val)
{	
	DP_Cookies.setNVP('KhovSessionPrefs','Music',val,'','/','',false);
	pageTracker._trackPageview('Music '+val);
}


function restartGif()
{
	for(var i=0; i<document.images.length; i++)
	{
	     	var img = document.images[i];
	     	var imgName = img.src.toUpperCase();
	     	if (imgName.substring(imgName.length-3, imgName.length) == "GIF")
		{
		     img.src = img.src;
     		}
	}
}









/*  DepressedPress.com DP_Cookies

Author: Jim Davis, the Depressed Press of Boston
Date: June 28, 2006
Contact: webmaster@depressedpress.com
Website: www.depressedpress.com

Full documentation can be found at:
http://www.depressedpress.com/Content/Development/JavaScript/Extensions/

DP_Cookies abstracts client-side cookie processing and management into a simplified, object-oriented interface.

Copyright (c) 1996-2006, The Depressed Press of Boston (depressedpress.com)

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

+) Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 

+) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 

+) Neither the name of the DEPRESSED PRESS OF BOSTON (DEPRESSEDPRESS.COM) nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/

DP_Cookies = new Object();

DP_Cookies.enabled = function() {

	return navigator.cookieEnabled

};

DP_Cookies.setNVP = function(CookieName, Name, Value, Expiry, Path, Domain, Secure)
{
	var exp1= new RegExp(Name+"=");
	var str1= unescape(DP_Cookies.get(CookieName));
	var exp2= new RegExp(Name+"="+DP_QueryString.get(Name,'array','?'+unescape(str1)));
	var str2= Name+"="+Value;

	if(DP_Cookies.get(CookieName)==null)
	{
		DP_Cookies.set(CookieName, Name+"="+Value, Expiry, Path, Domain, Secure);
	}
	else
	{

		if(exp1.test(unescape(DP_Cookies.get(CookieName))))
		{
			DP_Cookies.set(CookieName, str1.replace(exp2,str2), Expiry, Path, Domain, Secure);	
		}
		else
		{
			if(DP_Cookies.get(CookieName)=="")
			{
				DP_Cookies.set(CookieName, Name+"="+Value, Expiry, Path, Domain, Secure);
			}
			else
			{
				DP_Cookies.set(CookieName, unescape(DP_Cookies.get(CookieName))+"&"+Name+"="+Value, Expiry, Path, Domain, Secure);
			}
		}
	}


}

DP_Cookies.getNVP = function(CookieName, Name) {

	CookieName = CookieName.replace(/^\s*|\s*$/g,"");
	
	var arrArgs = new Array();
	var Cookies = document.cookie.split(";");

	for ( var Cnt=0; Cnt < Cookies.length; Cnt++ ) {
		var CurCookie = Cookies[Cnt].split("=");
		if ( CurCookie[0].replace(/^\s*|\s*$/g,"") == CookieName ) {
			if ( CurCookie[1]!='') {
				return DP_QueryString.get(Name,'array', '?'+unescape(Cookies[Cnt]));
			} else {
				return "";
			};
		};
	};

	return null;

};


DP_Cookies.set = function( name, value, expires, path, domain, secure ) 
{
// set time, it's in milliseconds
var today = new Date();
today.setTime( today.getTime() );

/*
if the expires variable is set, make the correct 
expires time, the current script below will set 
it for x number of days, to make it for hours, 
delete * 24, for minutes, delete * 60 * 24
*/
if ( expires )
{
expires = expires * 1000 * 60 * 60 * 24;
}
var expires_date = new Date( today.getTime() + (expires) );

document.cookie = name + "=" + value +
( ( expires ) ? ";expires=" + expires_date.toGMTString() : "" ) + 
( ( path ) ? ";path=" + path : "" ) + 
( ( domain ) ? ";domain=" + domain : "" ) +
( ( secure ) ? ";secure" : "" );
}




DP_Cookies.deprecated = function(Name, Value, Timespan, TimespanUnit, Domain, Path, Secure) {

		// Set the Name
	Name = Name.replace(/^\s*|\s*$/g,"");
		// Set the Value
	//if ( Value ) { Value = escape(Value) } else { Value="" };
	if ( Value ) { Value = Value } else { Value="" };

		// Set the Expires Value
	if ( typeof Timespan == "number" ) {
		var CurDate = new Date();
		switch (TimespanUnit) {
			case "days":
				Timespan = Timespan * 24 * 60 * 60 * 1000;
				break;
			case "hours":
				Timespan = Timespan * 60 * 60 * 1000;
				break;
			case "minutes":
				Timespan = Timespan * 60 * 1000;
				break;
			case "seconds":
				Timespan = Timespan * 1000;
				break;
			default:
				Timespan = Timespan * 24 * 60 * 60 * 1000;
				break;
		};
		CurDate.setTime(CurDate.getTime() + Timespan);
		var Expires = "; expires=" + CurDate.toGMTString();
	} else {
		var Expires = "";
	};

	Set_Cookie(Name,Value,'','/','',false);

	// Return the cookie
	return CookieValue;
};


function Set_Cookie( name, value, expires, path, domain, secure ) 
{
// set time, it's in milliseconds
var today = new Date();
today.setTime( today.getTime() );

/*
if the expires variable is set, make the correct 
expires time, the current script below will set 
it for x number of days, to make it for hours, 
delete * 24, for minutes, delete * 60 * 24
*/
if ( expires )
{
expires = expires * 1000 * 60 * 60 * 24;
}
var expires_date = new Date( today.getTime() + (expires) );

document.cookie = name + "=" + value +
( ( expires ) ? ";expires=" + expires_date.toGMTString() : "" ) + 
( ( path ) ? ";path=" + path : "" ) + 
( ( domain ) ? ";domain=" + domain : "" ) +
( ( secure ) ? ";secure" : "" );
}



DP_Cookies.eraseAll = function() {

	var Cookies = document.cookie.split(";");

	for ( var Cnt=0; Cnt < Cookies.length; Cnt++ ) {
		var CurCookie = Cookies[Cnt].split("=");
		if ( CurCookie[0] ) {
			this.set(CurCookie[0].replace(/^\s*|\s*$/g,""), "", -1);
		};
	};

		// Return "true"
	return true;

};

DP_Cookies.get = function(Name) {

		// Set the Name
	Name = Name.replace(/^\s*|\s*$/g,"");

	var Cookies = document.cookie.split(";");
	var exp1 = new RegExp(Name+"=");
	var str1;

	for ( var Cnt=0; Cnt < Cookies.length; Cnt++ ) {
	str1=Cookies[Cnt];
		var CurCookie = Cookies[Cnt].split("=");
		if ( CurCookie[0].replace(/^\s*|\s*$/g,"") == Name ) {
			if ( CurCookie[1] ) {
				str1=str1.replace(exp1,'')
				//alert(str1);
				//return CurCookie[1];
				return str1;	
			} else {
				return "";
			};
		};
	};

	return null;

};

DP_Cookies.getAll = function() {

	var AllCookies = new Object;
	var Cookies = document.cookie.split(";");

	for ( var Cnt=0; Cnt < Cookies.length; Cnt++ ) {
		var CurCookie = Cookies[Cnt].split("=");
		if ( CurCookie[0] ) {
			if ( CurCookie[1] ) {
				AllCookies[CurCookie[0].replace(/^\s*|\s*$/g,"")] = DP_Cookies.get(CurCookie[0]);
			} else {
				AllCookies[CurCookie[0].replace(/^\s*|\s*$/g,"")] = "";
			};
		};
	};

	return AllCookies;

};



/*  DepressedPress.com DP_QueryString

Author: Jim Davis, the Depressed Press of Boston
Date: June 28, 2006
Contact: webmaster@depressedpress.com
Website: www.depressedpress.com

Full documentation can be found at:
http://www.depressedpress.com/Content/Development/JavaScript/Extensions/

DP_QueryString abstracts query string (also called "URL variables" or "command line variables") processing and management into a simplified, object-oriented interface.

Copyright (c) 1996-2006, The Depressed Press of Boston (depressedpress.com)

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

+) Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 

+) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 

+) Neither the name of the DEPRESSED PRESS OF BOSTON (DEPRESSEDPRESS.COM) nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/

DP_QueryString = new Object();

DP_QueryString.get = function(Name, ReturnStyle, QueryString) {

	var AllElements, CurElement, CurName, CurVal, ReturnVal

		// Set the Name
	Name = Name.replace(/^\s*|\s*$/g,"");
		// Init the return
	ReturnVal = null;

		// Determine the string to use
	if ( !QueryString ) {
		QueryString = location.search;
	};
		// Split the query string on the ampersand (the substring removes the question mark)
	AllElements = QueryString.substring(1).split('&');

		// Loop over the string
	for( var Cnt = 0; Cnt < AllElements.length; Cnt++) {
			// Split the current element on the equals sign
		CurElement = AllElements[Cnt].split('=');
			// Unescape and Trim the returned name
		CurName = unescape(CurElement[0]).replace(/^\s*|\s*$/g,"");
		if ( Name == CurName ) {
				// Generate the array if needed
			if ( !ReturnVal ) { ReturnVal = new Array };
				// Get the Value
			CurVal = CurElement[1];
				// Determine how the value should be represented
			if ( CurVal ) {
				CurVal = unescape(CurVal);
			} else {
				CurVal = "";
			};
			ReturnVal[ReturnVal.length] = CurVal;
		};
	};

		// Return the value
	if ( ReturnVal ) {
		switch ( ReturnStyle ) {
			case "first":
				return ReturnVal[0];
				break;
			case "last":
				return ReturnVal[ReturnVal.length - 1];
				break;
			case "list":
				return ReturnVal.toString();
				break;
			default:
				return ReturnVal;
				break
		};
	} else {
		return ReturnVal;
	};

};

DP_QueryString.getAll = function(ReturnStyle, QueryString) {

	var QS, AllElements, CurElement, CurName, CurVal

	QS = new Object();

		// Determine the string to use
	if ( !QueryString ) {
		QueryString = location.search;
	};
		// Split the query string on the ampersand (the substring removes the question mark)
	AllElements = QueryString.substring(1).split('&');
	
		// Loop over the elements
	for( var Cnt = 0; Cnt < AllElements.length; Cnt++) {
			// Split the current element on the equals sign
		CurElement = AllElements[Cnt].split('=');
		CurName = unescape(CurElement[0]).replace(/^\s*|\s*$/g,"");
			// Call the get method to obtain the value

		if ( CurName.length > 0 ) {
			QS[CurName] = DP_QueryString.get(CurName, ReturnStyle);
		};
	};
		// Return the object
	return QS;
};



DP_QueryString.generate = function(Ob) {

	var QS = "?";

		// Sub Function to create the Params
	var generateParam = function(CurProp, CurVal) {
		if (!CurVal) {
			return escape(CurProp) + "&";
		} else {
			return CurProp + "=" + escape(CurVal) + "&";
		};
	};

		// Iterate over the passed object
	for ( var CurProp in Ob ) {
		if ( typeof Ob[CurProp] != "function" ) {
			var CurVal = Ob[CurProp];
			if ( typeof CurVal == "object" && CurVal.constructor == Array ) {
				for ( var Cnt = 0; Cnt < CurVal.length; Cnt++ ) {
					QS += generateParam(CurProp, CurVal[Cnt]);
				};
			} else {
				if ( CurVal != undefined ) {
					QS += generateParam(CurProp, CurVal);
				};
			};
		};
	};

		// Return the object (removing the last ampersand)
	return QS.substring(0, QS.length - 1);

};




/**
 * http://www.openjs.com/scripts/events/keyboard_shortcuts/
 * Version : 2.01.B
 * By Binny V A
 * License : BSD
 */
shortcut = {
	'all_shortcuts':{},//All the shortcuts are stored in this array
	'add': function(shortcut_combination,callback,opt) {
		//Provide a set of default options
		var default_options = {
			'type':'keydown',
			'propagate':false,
			'disable_in_input':false,
			'target':document,
			'keycode':false
		}
		if(!opt) opt = default_options;
		else {
			for(var dfo in default_options) {
				if(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo];
			}
		}

		var ele = opt.target;
		if(typeof opt.target == 'string') ele = document.getElementById(opt.target);
		var ths = this;
		shortcut_combination = shortcut_combination.toLowerCase();

		//The function to be called at keypress
		var func = function(e) {
			e = e || window.event;
			
			if(opt['disable_in_input']) { //Don't enable shortcut keys in Input, Textarea fields
				var element;
				if(e.target) element=e.target;
				else if(e.srcElement) element=e.srcElement;
				if(element.nodeType==3) element=element.parentNode;

				if(element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') return;
			}
	
			//Find Which key is pressed
			if (e.keyCode) code = e.keyCode;
			else if (e.which) code = e.which;
			var character = String.fromCharCode(code).toLowerCase();
			
			if(code == 188) character=","; //If the user presses , when the type is onkeydown
			if(code == 190) character="."; //If the user presses , when the type is onkeydown

			var keys = shortcut_combination.split("+");
			//Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked
			var kp = 0;
			
			//Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken
			var shift_nums = {
				"`":"~",
				"1":"!",
				"2":"@",
				"3":"#",
				"4":"$",
				"5":"%",
				"6":"^",
				"7":"&",
				"8":"*",
				"9":"(",
				"0":")",
				"-":"_",
				"=":"+",
				";":":",
				"'":"\"",
				",":"<",
				".":">",
				"/":"?",
				"\\":"|"
			}
			//Special Keys - and their codes
			var special_keys = {
				'esc':27,
				'escape':27,
				'tab':9,
				'space':32,
				'return':13,
				'enter':13,
				'backspace':8,
	
				'scrolllock':145,
				'scroll_lock':145,
				'scroll':145,
				'capslock':20,
				'caps_lock':20,
				'caps':20,
				'numlock':144,
				'num_lock':144,
				'num':144,
				
				'pause':19,
				'break':19,
				
				'insert':45,
				'home':36,
				'delete':46,
				'end':35,
				
				'pageup':33,
				'page_up':33,
				'pu':33,
	
				'pagedown':34,
				'page_down':34,
				'pd':34,
	
				'left':37,
				'up':38,
				'right':39,
				'down':40,
	
				'f1':112,
				'f2':113,
				'f3':114,
				'f4':115,
				'f5':116,
				'f6':117,
				'f7':118,
				'f8':119,
				'f9':120,
				'f10':121,
				'f11':122,
				'f12':123
			}
	
			var modifiers = { 
				shift: { wanted:false, pressed:false},
				ctrl : { wanted:false, pressed:false},
				alt  : { wanted:false, pressed:false},
				meta : { wanted:false, pressed:false}	//Meta is Mac specific
			};
                        
			if(e.ctrlKey)	modifiers.ctrl.pressed = true;
			if(e.shiftKey)	modifiers.shift.pressed = true;
			if(e.altKey)	modifiers.alt.pressed = true;
			if(e.metaKey)   modifiers.meta.pressed = true;
                        
			for(var i=0; k=keys[i],i<keys.length; i++) {
				//Modifiers
				if(k == 'ctrl' || k == 'control') {
					kp++;
					modifiers.ctrl.wanted = true;

				} else if(k == 'shift') {
					kp++;
					modifiers.shift.wanted = true;

				} else if(k == 'alt') {
					kp++;
					modifiers.alt.wanted = true;
				} else if(k == 'meta') {
					kp++;
					modifiers.meta.wanted = true;
				} else if(k.length > 1) { //If it is a special key
					if(special_keys[k] == code) kp++;
					
				} else if(opt['keycode']) {
					if(opt['keycode'] == code) kp++;

				} else { //The special keys did not match
					if(character == k) kp++;
					else {
						if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase
							character = shift_nums[character]; 
							if(character == k) kp++;
						}
					}
				}
			}
			
			if(kp == keys.length && 
						modifiers.ctrl.pressed == modifiers.ctrl.wanted &&
						modifiers.shift.pressed == modifiers.shift.wanted &&
						modifiers.alt.pressed == modifiers.alt.wanted &&
						modifiers.meta.pressed == modifiers.meta.wanted) {
				callback(e);
	
				if(!opt['propagate']) { //Stop the event
					//e.cancelBubble is supported by IE - this will kill the bubbling process.
					e.cancelBubble = true;
					e.returnValue = false;
	
					//e.stopPropagation works in Firefox.
					if (e.stopPropagation) {
						e.stopPropagation();
						e.preventDefault();
					}
					return false;
				}
			}
		}
		this.all_shortcuts[shortcut_combination] = {
			'callback':func, 
			'target':ele, 
			'event': opt['type']
		};
		//Attach the function with the event
		if(ele.addEventListener) ele.addEventListener(opt['type'], func, false);
		else if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func);
		else ele['on'+opt['type']] = func;
	},

	//Remove the shortcut - just specify the shortcut and I will remove the binding
	'remove':function(shortcut_combination) {
		shortcut_combination = shortcut_combination.toLowerCase();
		var binding = this.all_shortcuts[shortcut_combination];
		delete(this.all_shortcuts[shortcut_combination])
		if(!binding) return;
		var type = binding['event'];
		var ele = binding['target'];
		var callback = binding['callback'];

		if(ele.detachEvent) ele.detachEvent('on'+type, callback);
		else if(ele.removeEventListener) ele.removeEventListener(type, callback, false);
		else ele['on'+type] = false;
	}
}