/******************************************************************************
 The DM Object v1.3
 
 The DM Object inspired by SI Object (http://www.shauninman.com/).
 
 Stores a variety of functions localized to modules. Any module that requires
 initialization onload should have an onload handler. The DM.onload method will
 loop through all modules and run their respective onload handler. DM.onload
 can then be called in the window.onload event handler and all modules requiring
 initialization will be initialized. Does the same for onbeforeload and unload.
 
 v1.0 : Initial creation
 v1.1 : Added SideNav module
 v1.2 : Added Class, DynamicMap, EventsCalendar and FadeAnything modules
 v1.3 : Added SolutionFeatures module
 v1.4 : Added ParseLinks module
 
 ******************************************************************************/

if (!DM) { var DM = new Object(); };
DM.hasRequired 	= function() {
	if (document.getElementById && document.getElementsByTagName) {
		var html = document.getElementsByTagName('html')[0];
		html.className += ((html.className=='')?'':' ')+'has-dom';
		return true;
	};
	return false;
}();
DM.onbeforeload	= function() { if (this.hasRequired) { for (var module in this) { if (this[module].onbeforeload) { this[module].onbeforeload();	};};};};
DM.onload		= function() { if (this.hasRequired) { for (var module in this) { if (this[module].onload) { this[module].onload(); };};};};
DM.onunload		= function() { if (this.hasRequired) { for (var module in this) { if (this[module].onunload) { this[module].onunload(); };};};};


/******************************************************************************
 DM.SimulateSelectors module v1.3
 
 Adds CSS :first/last-child support for IE via classnames to unordered lists.
 
 v1.0 : Initial creation
 v1.1 : Added span with 'before' class and a pipe character and space list items
        in the footer element's list. Mimmicks the li's :before selector and the
        'content' property.
 v1.2 : Added more complete support for :before/after pseudo selectors including
        getting the content property from the stylesheet.
 v1.3 : Made the regular expression to find the content of the "content" property
        lazy instead of greedy. Should prevent problems finding the real content.
 
 ******************************************************************************/
DM.SimulateSelectors = {
	onbeforeload		: function() {
		if (document.all) {
			var lists = document.getElementsByTagName('ul');
			
			for (var i=0; list=lists[i]; i++) {
				for (j=0; listItem=list.childNodes[j]; j++) {
					if (listItem.nodeName != 'LI') { continue; };
					if (j==0) { listItem.className += ((listItem.className=='')?'':' ')+'first'; };
					if (j==list.childNodes.length-1) { listItem.className += ((listItem.className=='')?'':' ')+'last'; };
				};
			};
			
			
			if (document.styleSheets) {
				var sheets = document.styleSheets, sl = sheets.length;
				
				for (var i=0; i<sl; i++) {
					var sheet = sheets[i];
					var rules = (currentSheet = sheet).rules, rl = rules.length;
					
					for (var j=0; j<rl; j++) {
						var rule = rules[j];
						var select = rule.selectorText, style = rule.style.cssText.replace(/; /g, ';\n') + ';', styleArr = style.split('\n'), sal = styleArr.length;
						
						if (style.indexOf('content:')!=-1 && select.indexOf('.clearfix')==-1) {
							for (var k=0; k<sal; k++) {
								if (styleArr[k].indexOf('content:')!=-1) {
									var content = styleArr[k].replace(/content: "([^"]+?)";/, '$1');
									var affected = select.replace(/:(hover|active|unknown).*$/, '');
									var elements = this.getElementsBySelect(affected);
									
									for (var l=0; element=elements[l]; l++) {
										var b = document.createElement('span');
										b.className	= (select.indexOf('#footer')!=-1)?'before':'after';
										b.innerHTML	= content;
										if (b.className=='before') {
											element.insertBefore(b, element.firstChild);
										} else {
											element.appendChild(b);
										};
									};
								};
							};
						};
					};
				};
			};
		};
	},
	getElementsBySelect	: function (rule) {
		var parts, nodes = [document];
		parts = rule.split(' ');
		
		for (var i=0; i<parts.length; i++) {
			nodes = this.getSelectedNodes(parts[i], nodes);
		};
		
		return nodes;
	},
	getSelectedNodes	: function (select, elements) {
		var result, node, nodes = [];
		var identify = (/\#([a-z0-9_-]+)/i).exec(select);
		
		if (identify) {
			var element = document.getElementById(identify[1]);
			return element? [element]:nodes;
		};
		
		var classname = (/\.([a-z0-9_-]+)/i).exec(select);
		var tagName = select.replace(/(\.|\#|\:)[a-z0-9_-]+/i, '');
		var classReg = classname? new RegExp('\\b' + classname[1] + '\\b'):false;
		
		for (var i=0; i<elements.length; i++) {
			result = tagName? elements[i].all.tags(tagName):elements[i].all;
			for (var j=0; j<result.length; j++) {
				node = result[j];
				if (classReg && !classReg.test(node.className)) { continue; };
				nodes[nodes.length] = node;
			};
		};
		
		return nodes;
	}
};
	
	
/******************************************************************************
 DM.PrintWindow module v1.0
 
 ******************************************************************************/
DM.PrintWindow = function() {
	window.print?window.print():alert('Your browser doesn\'t support this funtion. Please select \'File > Print\' from your browser\'s menu to print this page.');
};
	
	
/******************************************************************************
 DM.SendToAFriend module v1.0
 
 ******************************************************************************/
DM.SendToAFriend = function(url) {
	var win = window.open(url, 'SendToAFriend', 'width=373, height=320');
	if (window.focus) { win.focus(); };
};


/******************************************************************************
 DM.Class module v1.0
 
 Provides helper functions for adding/removing/testing for classes.
 
 ******************************************************************************/
DM.Class = {
	add		: function (obj,cName) { this.kill(obj,cName); return obj && (obj.className+=(obj.className.length>0?' ':'')+cName); },
	kill	: function (obj,cName) { return obj && (obj.className=obj.className.replace(new RegExp("^"+cName+"\\b\\s*|\\s*\\b"+cName+"\\b",'g'),'')); },
	has		: function (obj,cName) { return (!obj || !obj.className)?false:(new RegExp("\\b"+cName+"\\b")).test(obj.className) }
};


/******************************************************************************
 DM.ParseLinks module v1.0
 
 Opens external links in a new window and adds classes to document type links
 (pdf, doc, etc) in the body content of the page.
 
 ******************************************************************************/
DM.ParseLinks = {
	page			: {contentid: 'container', tag: 'a'},
	onbeforeload	: function () {
		if (document.getElementById(this.page.contentid)) {
			var links = document.getElementById(this.page.contentid).getElementsByTagName(this.page.tag);
			var domain = document.location.href.replace(/^https?:\/\/([^\/]+)\/.*$/, '$1');
			
			for (i=0; link=links[i]; i++) {
				if (link.href&&link.href.indexOf('mailto')==-1&&(link.firstChild&&link.firstChild.nodeName!='IMG')) {
					var ext = String(link.href).substring(String(link.href).length, String(link.href).length - 3);
					if (ext=='pdf'||ext=='doc') {
						if (link.parentNode.nodeName!='DD') { DM.Class.add(link, 'document-small'); };
						link.onclick = function() {
							window.open(this.href);
							return false;
						};
					} else if (link.href.indexOf(domain)==-1) {
						DM.Class.add(link, 'external-small');
						link.onclick = function() {
							window.open(this.href);
							return false;
						};
					};
				};
			};
		};
	}
};


/******************************************************************************
 DM.StyleSwitch module v1.0
 
 Manages the font size up/down feature.
 
 v1.0 : Initial creation
 
 ******************************************************************************/
DM.StyleSwitch = {
	preferred		: 'A-',
	fontsizeup		: function() {
		active = this.getActive();
		if (active == 'A--') {
			this.setActive('A-');
		} else if (active == 'A-') {
			this.setActive('A');
		} else if (active == 'A') {
			this.setActive('A+');
		} else if (active == 'A+') {
			this.setActive('A++');
		} else if (active == 'A++') {
			// Do nothing
		} else {
			this.setActive('A');
		};
	},
	fontsizedown	: function() {
		active = this.getActive();
		if (active == 'A++') {
			this.setActive('A+');
		} else if (active == 'A+') {
			this.setActive('A');
		} else if (active == 'A') {
			this.setActive('A-');
		} else if (active == 'A-') {
			this.setActive('A--');
		} else if (active == 'A--') {
			// Do nothing
		} else {
			this.setActive('A--');
		}
	},
	setActive		: function(title) {
		var i, a, main;
		for(i=0; (a = document.getElementsByTagName("link")[i]); i++) {
			if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("title")) {
				a.disabled = true;
				if(a.getAttribute("title") == title) a.disabled = false;
			}
		}
	},
	getActive		: function() {
		var i, a;
		for(i=0; (a = document.getElementsByTagName("link")[i]); i++) {
			if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("title") && !a.disabled) return a.getAttribute("title");
		}
		return null;
	},
	createCookie	: function(name,value,days) {
		if (days) {
			var date = new Date();
			date.setTime(date.getTime()+(days*24*60*60*1000));
			var expires = "; expires="+date.toGMTString();
		} else expires = "";
		document.cookie = name+"="+value+expires+"; path=/";
	},
	readCookie		: function(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;
	},
	onbeforeload	: function() {
		var cookie = this.readCookie("style");
		var title = cookie?cookie:this.preferred;
		if (title == 'null') { title = this.preferred; };
		this.setActive(title);
	},
	onload			: function() {
		var cookie = this.readCookie("style");
		var title = cookie?cookie:this.preferred;

		this.setActive(title);
	},
	onunload		: function() {
		var title = this.getActive();
		this.createCookie("style", title, 365);
	}
};


/******************************************************************************
 DM.Tabs module v1.1
 
 This library is copyright 2004 by Gavin Kistner, gavin@refinery.com
 It is covered under the license viewable at http://phrogz.net/JS/_ReuseLicense.txt
 
 v1.0 : Imported Tabtastic code
 v1.1 : Rewrote the module to work within the DM Object
 
 TODO : Scrolling is already removed, but need to remove page offset code and add
        cookie to remember active tab in SetTabFromAnchor.
 
 ******************************************************************************/
DM.Tabs	= {
	tocTag				: 'ul',
	tocClass			: 'tabset-tabs',
	tabTag				: 'a',
	AddClass			: function (obj,cName) { this.KillClass(obj,cName); return obj && (obj.className+=(obj.className.length>0?' ':'')+cName); },
	KillClass			: function (obj,cName) { return obj && (obj.className=obj.className.replace(new RegExp("^"+cName+"\\b\\s*|\\s*\\b"+cName+"\\b",'g'),'')); },
	HasClass			: function (obj,cName) { return (!obj || !obj.className)?false:(new RegExp("\\b"+cName+"\\b")).test(obj.className) },
	FindEl				: function (tagName, evt) {
		if (!evt && window.event) evt=event;
		if (!evt) return DebugOut("Can't find an event to handle in DLTabSet::SetTab",0);
		var el=evt.currentTarget || evt.srcElement;
		while (el && (!el.tagName || el.tagName.toLowerCase()!=tagName)) el=el.parentNode;
		return el;
	},
	SetTabActive		: function (tab) {
		if (tab.tabTOC.activeTab) {
			if (tab.tabTOC.activeTab==tab) return;
			this.KillClass(tab.tabTOC.activeTab,'active');
			if (tab.tabTOC.activeTab.tabContent) this.KillClass(tab.tabTOC.activeTab.tabContent,'tabset-content-active');
			//if (tab.tabTOC.activeTab.tabContent) tab.tabTOC.activeTab.tabContent.style.display='';
			if (tab.tabTOC.activeTab.prevTab) this.KillClass(tab.tabTOC.activeTab.previousTab,'pre-active');
			if (tab.tabTOC.activeTab.nextTab) this.KillClass(tab.tabTOC.activeTab.nextTab,'post-active');
		}
		this.AddClass(tab.tabTOC.activeTab=tab,'active');
		if (tab.tabContent) this.AddClass(tab.tabContent,'tabset-content-active');				
		//if (tab.tabContent) tab.tabContent.style.display='block';
		if (tab.prevTab) this.AddClass(tab.prevTab,'pre-active');
		if (tab.nextTab) this.AddClass(tab.nextTab,'post-active');
	},
	SetTabFromAnchor	: function (evt) {
		if (window.pageYOffset) {
			  pos = window.pageYOffset
		} else if (document.documentElement && document.documentElement.scrollTop) {
			pos = document.documentElement.scrollTop
		} else if (document.body) {
			  pos = document.body.scrollTop
		}
		//setTimeout('document.body.scrollTop='+document.body.scrollTop,1);
		setTimeout('window.scrollTo(0,'+pos+')',1);
		DM.Tabs.SetTabActive(DM.Tabs.FindEl('a',evt).semanticTab);
		this.blur();
		return false;
	},
	onbeforeload		: function () {
		window.everyTabThereIsById = {};
		
		var anchorMatch = /#([a-z][\w.:-]*)$/i,match;
		var activeTabs = [];
		
		var tocs = document.getElementsByTagName(this.tocTag);
		for (var i=0,len=tocs.length;i<len;i++){
			var toc = tocs[i];
			if (!this.HasClass(toc,this.tocClass)) continue;

			var lastTab;
			var tabs = toc.getElementsByTagName(this.tabTag);
			for (var j=0,len2=tabs.length;j<len2;j++){
				var tab = tabs[j];
				if (!tab.href || !(match=anchorMatch.exec(tab.href))) continue;
				if (lastTab){
					tab.prevTab=lastTab;
					lastTab.nextTab=tab;
				}
				tab.tabTOC=toc;
				everyTabThereIsById[tab.tabID=match[1]]=tab;
				tab.tabContent = document.getElementById(tab.tabID);
				
				if (this.HasClass(tab,'active')) activeTabs[activeTabs.length]=tab;
				
				lastTab=tab;
			}
			this.AddClass(toc.getElementsByTagName('li')[0],'first-child');
		}

		for (var i=0,len=activeTabs.length;i<len;i++){
			this.SetTabActive(activeTabs[i]);
		}

		for (var i=0,len=document.links.length;i<len;i++){
			var a = document.links[i];
			if (!(match=anchorMatch.exec(a.href))) continue;
			if (a.semanticTab = everyTabThereIsById[match[1]]) a.onclick = this.SetTabFromAnchor;
		}
		
		if ((match=anchorMatch.exec(location.href)) && (a=everyTabThereIsById[match[1]])) this.SetTabActive(a);
		
	}
};


/******************************************************************************
 DM.SideNav module v1.3
 
 Manages the expanding/collapsing side nav
 
 v1.0 : Initial creation
 v1.1 : Now uses DM.Class module instead of duplicated functions
 v1.2 : Added fix for IE which doesn't recognise an anchor unless it has a href
 v1.3 : Added auto-highlight function when focus is given to ASX email field
 
 ******************************************************************************/
DM.SideNav = {
	sidenav			: {id: 'side', expanded: 'expanded', collapsed: 'collapsed', active: 'active'},
	toggle			: function () {
		if (DM.Class.has(this.parentNode, DM.SideNav.sidenav.collapsed)) {
			DM.Class.kill(this.parentNode, DM.SideNav.sidenav.collapsed);
			DM.Class.add(this.parentNode, DM.SideNav.sidenav.expanded);
		} else if (DM.Class.has(this.parentNode, DM.SideNav.sidenav.expanded)) {
			DM.Class.kill(this.parentNode, DM.SideNav.sidenav.expanded);
			DM.Class.add(this.parentNode, DM.SideNav.sidenav.collapsed);
		};
		return false;
	},
	onbeforeload	: function () {
		if (document.getElementById(this.sidenav.id)) {
			var links = document.getElementById(this.sidenav.id).getElementsByTagName('a');
			
			for (var i=0; link=links[i]; i++) {
				if (document.all && !link.href && (DM.Class.has(link.parentNode, this.sidenav.collapsed) || DM.Class.has(link.parentNode, this.sidenav.expanded))) { link.href = '#'; };
				if (DM.Class.has(link.parentNode, this.sidenav.collapsed) || DM.Class.has(link.parentNode, this.sidenav.expanded)) { link.onclick=this.toggle; };
				if (link.parentNode.nodeName=='LI' && link.href && link.href==document.location.href) { DM.Class.add(link.parentNode, this.sidenav.active); };
			};
		};
		
		if (emailField=document.getElementById('email')) {
			emailField.onfocus = function() { if (this.value=='Enter your email') { this.select(); }; };
		};
	}
};


/******************************************************************************
 DM.DynamicMap module v1.0
 
 Manages the map and it's tooltips
 
 v1.0 : Initial creation
 
 ******************************************************************************/
DM.DynamicMap = {
	hotspots		: {id: 'map-hotspots'},
	tooltips		: {tag: 'div', tclass: 'tooltip', active: 'active'},
	showtip			: function (tooltip) {
		DM.Class.add(tooltip, DM.DynamicMap.tooltips.active);
	},
	hidetip			: function (tooltip) {
		DM.Class.kill(tooltip, DM.DynamicMap.tooltips.active);
	},
	onbeforeload	: function () {
		if (document.getElementById(this.hotspots.id)) {
			window.everyTooltipThereIsById = {};
		
			var anchorMatch = /#([a-z][\w.:-]*)$/i,match;
			var tooltips = document.getElementsByTagName(this.tooltips.tag);
			
			for (var i=0; tooltip=tooltips[i]; i++) {
				if (DM.Class.has(tooltip, this.tooltips.tclass)) {
					if (!tooltip.id) { continue; };
					everyTooltipThereIsById[tooltip.id] = tooltip;
					tooltip.onmouseover = function () {
						window.clearTimeout(this.hidetipTimeout);
					};
					tooltip.onmouseout = function () {
						var tooltip = this;
						this.hidetipTimeout = window.setTimeout(function () { DM.DynamicMap.hidetip(tooltip); }, 1);
					};
				};
			};
		
			var hotspots = document.getElementById(this.hotspots.id).getElementsByTagName('area');
			
			for (var i=0; hotspot=hotspots[i]; i++) {
				if (!(match=anchorMatch.exec(hotspot.href))) { continue; };
				if (hotspot.semanticTip = everyTooltipThereIsById[match[1]]) {
					hotspot.onclick = function() { return false; };
					hotspot.onmouseover = function () {
						var tooltip = this.semanticTip;
						window.clearTimeout(tooltip.hidetipTimeout);
						DM.DynamicMap.showtip(tooltip);
					};
					hotspot.onmouseout = function () {
						var tooltip = this.semanticTip;
						tooltip.hidetipTimeout = window.setTimeout(function () { DM.DynamicMap.hidetip(tooltip); }, 1);
					};
				};
			};
		};
	}
};


/******************************************************************************
 DM.FadeAnything module v1.0
 
 Based on http://www.axentric.com/aside/fat/
 
 v1.0 : Imported Fat code
 
 ******************************************************************************/
DM.FadeAnything = {
	make_hex	: function (r,g,b) {
		r = r.toString(16); if (r.length == 1) { r = '0' + r; };
		g = g.toString(16); if (g.length == 1) { g = '0' + g; };
		b = b.toString(16); if (b.length == 1) { b = '0' + b; };
		return "#" + r + g + b;
	},
	fade_all	: function () {
		var a = document.getElementsByTagName("*");
		for (var i = 0; i < a.length; i++) {
			var o = a[i];
			var r = /fade-?(\w{3,6})?/.exec(o.className);
			if (r) {
				if (!r[1]) { r[1] = ""; };
				if (o.id) { this.fade_element(o.id,null,null,"#"+r[1]); };
			};
		};
	},
	fade_element : function (id, fps, duration, from, to) {
		if (!fps) { fps = 30; };
		if (!duration) { duration = 3000; };
		if (!from || from=="#") { from = "#FFFFD9"; };
		if (!to) { to = this.get_bgcolor(id); };
		
		var frames = Math.round(fps * (duration / 1000));
		var interval = duration / frames;
		var delay = interval;
		var frame = 0;
		
		if (from.length < 7) { from += from.substr(1,3); };
		if (to.length < 7) { to += to.substr(1,3); };
		
		var rf = parseInt(from.substr(1,2),16);
		var gf = parseInt(from.substr(3,2),16);
		var bf = parseInt(from.substr(5,2),16);
		var rt = parseInt(to.substr(1,2),16);
		var gt = parseInt(to.substr(3,2),16);
		var bt = parseInt(to.substr(5,2),16);
		
		var r,g,b,h;
		while (frame < frames) {
			r = Math.floor(rf * ((frames-frame)/frames) + rt * (frame/frames));
			g = Math.floor(gf * ((frames-frame)/frames) + gt * (frame/frames));
			b = Math.floor(bf * ((frames-frame)/frames) + bt * (frame/frames));
			h = this.make_hex(r,g,b);
		
			setTimeout("DM.FadeAnything.set_bgcolor('"+id+"','"+h+"')", delay);

			frame++;
			delay = interval * frame; 
		};
		setTimeout("DM.FadeAnything.set_bgcolor('"+id+"','"+to+"')", delay);
	},
	set_bgcolor : function (id, c) {
		var o = document.getElementById(id);
		o.style.backgroundColor = c;
	},
	get_bgcolor : function (id) {
		var o = document.getElementById(id);
		while(o) {
			var c;
			if (window.getComputedStyle) { c = window.getComputedStyle(o,null).getPropertyValue("background-color"); };
			if (o.currentStyle) { c = o.currentStyle.backgroundColor; };
			if ((c != "" && c != "transparent") || o.tagName == "BODY") { break; };
			o = o.parentNode;
		}
		if (c == undefined || c == "" || c == "transparent") { c = "#FFFFFF"; };
		var rgb = c.match(/rgb\s*\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)/);
		if (rgb) { c = this.make_hex(parseInt(rgb[1]),parseInt(rgb[2]),parseInt(rgb[3])); };
		return c;
	}
};


/******************************************************************************
 DM.EventsCalendar module v1.1
 
 Manages the events calendar
 
 v1.0 : Initial creation
 v1.1 : Removes the browser's standard tooltip
 
 ******************************************************************************/
DM.EventsCalendar = {
	source			: {id: 'e-calendar', tag: 'a', tooltipid: 'event-calendar-tooltip', tooltipparentid: 'wrapper'},
	show			: function (e) {
		var link = this, fromTop = 0, fromLeft = 0;
		var container = document.getElementById(DM.EventsCalendar.source.tooltipparentid);
		var tag = link;
		while (tag!=container) {
			fromTop += parseInt(tag.offsetTop);
			fromLeft += parseInt(tag.offsetLeft);
			tag = tag.offsetParent;
		}
		var d = document.createElement('div');
		d.style.position = 'absolute';
		d.style.top = fromTop + 'px';
		d.style.left = fromLeft + 'px';
		d.id = DM.EventsCalendar.source.tooltipid;
		var d2 = document.createElement('div');
		d.appendChild(d2);
		var p = document.createElement('p');
		p.innerHTML = link.title;
		d2.appendChild(p);
		container.appendChild(d);
		link.title = '';
	},
	hide			: function (e) {
		var link = this;
		if (d=document.getElementById(DM.EventsCalendar.source.tooltipid)) {
			link.title = d.getElementsByTagName('p')[0].innerHTML;
			d.parentNode.removeChild(d);
		};
	},
	onbeforeload	: function () {
		if (document.getElementById(this.source.id)) {
			var anchorMatch = /#([a-z][\w.:-]*)$/i,match;
			var links = document.getElementById(this.source.id).getElementsByTagName(this.source.tag);
			
			for (var i=0; link=links[i]; i++) {
				if (!(match=anchorMatch.exec(link.href))) { continue; };
				link.onclick = function () {
					var anchorMatch = /#([a-z][\w.:-]*)$/i,match;
					DM.FadeAnything.fade_element(match=anchorMatch.exec(this.href)[1], null, 2000, '#e7e7e7', '#ffffff');
				};
				link.onmouseover = this.show;
				link.onmouseout = this.hide;
			};
		};
	}
};


/******************************************************************************
 DM.SolutionFeatures module v1.2
 
 Manages the solution features page
 
 v1.0 : Initial creation
 v1.1 : Added checking for nav items heigher than the default height
 v1.2 : Changed functionality from onmouseover/onmouseout to onclick to allow
        easy scrolling on longer items.
 
 ******************************************************************************/
DM.SolutionFeatures = {
	source			: {id: 'solution-features-nav', tag: 'a', defaultheight: 20},
	target			: {id: 'solution-features-content', msgId: 'default-message', msg: 'Click on a feature in the list to view it&rsquo;s details.'},
	hideall			: function () {
		var anchorMatch = /#([a-z][\w.:-]*)$/i,match;
		var links = document.getElementById(DM.SolutionFeatures.source.id).getElementsByTagName(DM.SolutionFeatures.source.tag);
		
		for (var i=0; link=links[i]; i++) {
			if (!(match=anchorMatch.exec(link.href))) { continue; };
			if (document.getElementById(match=anchorMatch.exec(link.href)[1])) { DM.Class.add(document.getElementById(match), 'inactive'); };
		};
	},
	onbeforeload	: function () {
		if (document.getElementById(this.source.id)) {
			window.everyFeatureThereIsById = {};
			
			var anchorMatch = /#([a-z][\w.:-]*)$/i,match;
			var links = document.getElementById(this.source.id).getElementsByTagName(this.source.tag);
			
			for (var i=0; link=links[i]; i++) {
				if (!(match=anchorMatch.exec(link.href))) { continue; };
				if (link.parentNode.offsetHeight>this.source.defaultheight) { DM.Class.add(link.parentNode, 'doubleheight'); };
				if (document.getElementById(match=anchorMatch.exec(link.href)[1])) { DM.Class.add(document.getElementById(match), 'inactive'); };
				link.onclick = function () {
					DM.SolutionFeatures.hideall();
					var anchorMatch = /#([a-z][\w.:-]*)$/i,match;
					if (document.getElementById(match=anchorMatch.exec(this.href)[1])) {
						DM.Class.add(document.getElementById(DM.SolutionFeatures.target.msgId), 'inactive');
						DM.Class.kill(document.getElementById(match), 'inactive');
					};
					this.blur();
					return false;
				};
			};
			
			if (document.getElementById(this.target.id)) {
				var p = document.createElement('p');
				p.id = this.target.msgId;
				p.innerHTML = this.target.msg;
				document.getElementById(this.target.id).appendChild(p);
			};
		};
	}
};


/******************************************************************************
 window.onload/onunload()
 
 This should only ever require DM.onload()/onunload() which in turn initialises
 all modules that require it.
 
 ******************************************************************************/
window.onload	= function() { DM.onload(); };
window.onunload	= function() { DM.onunload(); };