/******************************************************************************
 The SI Object v2.4
 
 Use http://hometown.aol.de/_ht_a/memtronic/ to recompress
 
 Stores a variety of functions localized to modules. Any module that requires
 initialization onload should have an onload handler. The SI.onload method will
 loop through all modules and run their respective onload handler. SI.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 onresize.
 
 v2.1 : Added check for base function requirements, and Flash
 v2.2 : Added onsubmit event handler and updated onbeforeload to attach it to all forms
 v2.3 : Added onCSSload event handler and releated CSSattach/CSSwatch
 v2.4 : Changed `onCSSload` to `oncssload` for consistency
 
 ******************************************************************************/
if (!SI) { var SI = new Object(); };
SI.hasRequired 	= function() { 
	if (document.getElementById && document.getElementsByTagName) {
		var html = document.getElementsByTagName('html')[0];
		html.className += ((html.className=='')?'':' ')+'has-dom';
		return true;
		};
	return false;
	}();
SI.hasFlash		= function() {
	var flashVersion = 0;
	var required = 6;
	var m =16; // maximum version to test for
	var ua = navigator.userAgent.toLowerCase();
	if (navigator.plugins && navigator.plugins.length) {
		var p = navigator.plugins['Shockwave Flash'];
		if (typeof p == 'object') {
			for (var i=m;i>=3;i--) {
				if (p.description && p.description.indexOf(i + '.') != -1) { flashVersion = i; break; };
				};
			};
		}
	else if (window.ActiveXObject && window.print) {
		var found = false;
		for (var i=m; i>=3 && !found; i--) {
			try {
				found = eval("new ActiveXObject('ShockwaveFlash.ShockwaveFlash." + i + "');");
				if(found) { flashVersion = i; };
				}
			catch(e) {};
			};
		};
	if (required<flashVersion) {
		var html = document.getElementsByTagName('html')[0];
		html.className += ((html.className=='')?'':' ')+'has-flash';
		return true;
		};
	return false;
	}();
SI.onbeforeload	= function() {
	if (this.hasRequired) {
		this.CSSattach();
		var attachOnSubmit = false;

		for (var module in this) { 
			if (this[module].onbeforeload) { 
				this[module].onbeforeload();
				};
			if (this[module].onsubmit) { attachOnSubmit = true; };
			};
		
		if (attachOnSubmit) {
			var forms = document.getElementsByTagName('form');
			for (var i=0; form=forms[i]; i++) {
				if (typeof form.onsubmit!='function') {
					form.onsubmit = function() { return SI.onsubmit(this); };
					};
				};
			};
		};
	SI.Debug.output('Onbeforeload complete.',1);
	};
SI.onload		= function() { SI.Debug.output('Onload fired.',1); if (this.hasRequired) { for (var module in this) { if (this[module].onload) { this[module].onload(); };};};};
SI.onresize		= function() { SI.Debug.output('Onresize fired.',1); if (this.hasRequired) { for (var module in this) { if (this[module].onresize) { this[module].onresize(); };};};};
SI.onsubmit		= function(form) { SI.Debug.output('SI.onsubmit fired from '+form.id,1); for (var module in this) { if (this[module].onsubmit) { if (this[module].onsubmit(form)==false) { return false; };};}; return true; };
SI.oncssload	= function() { SI.Debug.output('Oncssload fired.',1); if (this.hasRequired) { for (var module in this) { if (this[module].oncssload) { this[module].oncssload(); };};};};
/* Support functions of onCSSload event handler */
SI.CSSattach	= function() {
	var d=document.createElement('div'),s=d.style;
	s.position		= 'fixed';
	s.top			= '0';
	s.visibility	= 'hidden';
	s.width			= '600px';
	s.height		= '16px';
	d.id='SI-CSS-seed';
	document.body.appendChild(d);
	window.setTimeout('SI.CSSwatch()',0);
	};
SI.CSSwatch			= function() {
	SI.Debug.output('Waiting for CSS to load...');
	var d = document.getElementById('SI-CSS-seed');
	if (d.offsetWidth<600) {
		var html = document.getElementsByTagName('html')[0];
		html.className += ((html.className=='')?'':' ')+'has-css';
		
		this.oncssload();
		d.parentNode.removeChild(d);
		}
	else { window.setTimeout('SI.CSSwatch()',1); };
	};


/******************************************************************************
 SI.Debug module v1.4
 
 Creates a div and writes to it. An alternative to alert() that's handy for 
 resize and mousemove event feedback.
 
 v1.1 : Added boolean debug to simplify toggling debugging on and off
 v1.2 : Added counter and rules. Elimated output length limit
 v1.3 : Added "Clear" button
 v1.4 : Add a second boolean argument to SI.Debug.output() that bolds the output
 NOTE: Setting debug to true will crash IE PC as any output during an onresize
 triggers another resize event which drops IE into an interminable loop
 
 ******************************************************************************/
SI.Debug = {
	debug			: false,
	e				: null,
	count			: 0,
	onbeforeload	: function() { 
		if (this.debug) {
			this.e = document.createElement('div');
			document.body.appendChild(this.e); 
			this.e.style.position 	= 'fixed';
			this.e.style.top 		= '16px';
			this.e.style.right 		= '16px';
			this.e.style.width 		= '360px';
			this.e.style.backgroundColor = '#EEE';
			this.e.style.border 	= '1px solid #DDD';
			this.e.style.padding 	= '12px';
			this.e.style.zIndex		= 10000;
			this.e.style.opacity 	= .8;
			
			var a = document.createElement('a');
			a.innerHTML = 'Clear Debug Output';
			a.href = '#Clear';
			a.e = document.createElement('div');
			a.onclick = function() {
				this.e.innerHTML='';
				return false;
				};
			this.e.appendChild(a);
			// e is now the inner div
			this.e = this.e.appendChild(a.e);
			};
		},
	output 			: function() { 
		if (this.debug && this.e!=null) {
			html = arguments[0];
			if (arguments.length==2) {
				html = '<strong>'+html+'</strong>';
				}
			var c = ++this.count;
			c = ((c<100)?'0':'')+((c<10)?'0':'')+c;
			
			this.e.innerHTML = '<hr />' + c + ': &nbsp; ' + html + this.e.innerHTML;
			};
		}
	};


/******************************************************************************
 SI.Resize module v2.0
 
 Resize creates a hidden div and monitors changes in it's offsetHeight to 
 determine when the user resizes text. This function doesn't modify any other
 elements, it augments the browsers default resize detection.

 ******************************************************************************/
SI.Resize = {
	control			: null,
	watchInterval	: 50,
	height			: 0,
	onbeforeload	: function() {
		if ((document.all && window.print) || !document.createElement) { return; };
		
		var c=document.createElement('div'),s=c.style;
		s.position		= 'fixed';
		s.top			= '0';
		s.visibility	= 'hidden';
		s.width			= '1em';
		s.height		= '1em';
		
		this.control = document.body.appendChild(c);
		this.height = 0;
		window.setInterval('SI.Resize.watch()',this.watchInterval);
		},
	watch			: function() {
		var o = this.height;
		this.height = this.control.offsetHeight;
		if (o!=this.height) this.react();
		},
	react			: function() {
		SI.onresize();
		}
	
	};


/******************************************************************************
 SI.CSS module v1.1
 
 Includes functions to add and remove CSS classes as well as functions to add
 relationship (first-, only-, and last-child) and alt classes. Also has a simple,
 single CSS selector element grabber.
 
 v1.1 : relate now clears relational classes before applying
 		select now handles being passed arrays of selectors or a valid HTML element
 ******************************************************************************/
SI.CSS = {
	// operates on the children of the given element
	relate		: function() { // adds appropriate class to first, last and only child as well as alt
		if (!SI.hasRequired) { return; };
		
		var elems = this.select(arguments);
		for (var i=0; i<elems.length; i++) {
			var elem 	= elems[i];
			var alt 	= false;
			
			var children = [];
			// make sure we're dealing with real HTML elements
			if (elem.nodeName=='TABLE') { children = elem.getElementsByTagName('tr'); } // won't work with nested tables
			// else if (elem.nodeName=='UL' || elem.nodeName=='OL') { children = elem.getElementsByTagName('li'); }
			else {
				SI.Debug.output('Not a table: '+elem.nodeName+' (children: '+elem.childNodes.length+')',1);
				for (var j=0; j<elem.childNodes.length; j++) {
					if (elem.childNodes[j].nodeType==1) { children[children.length] = elem.childNodes[j]; };
					};
				};
			
			for (var j=0; j<children.length; j++) {
				var child = children[j];
				child.className = this.removeClass(child.className,'first-child','only-child','last-child','alt');
				if (children.length==1) { child.className = this.addClass(child.className,'only-child'); break; }
				else if (j==0) { child.className = this.addClass(child.className,'first-child'); }
				else if (j==children.length-1) { child.className = this.addClass(child.className,'last-child'); };
				if (alt) { child.className = this.addClass(child.className,'alt'); };
				alt=!alt;
				};
			};
		},
	// operates on the children of the given element
	alt		: function() { // pass any number of simple, single element CSS selectors
		if (!SI.hasRequired) { return; };
		var elems = this.select(arguments);
		for (var i=0; i<elems.length; i++) {
			var elem 	= elems[i];
			var alt 	= false;
			
			var children = elem.childNodes
			if (elem.nodeName=='TABLE') { children = elem.getElementsByTagName('tr'); };
			
			for (var j=0; j<children.length; j++) {
				var child = children[j];
				if (child.nodeType==1) { // make sure we're dealing with an HTML element
					if (alt) { child.className = this.addClass(child.className,'alt'); };
					alt=!alt;
					};
				};
			};
		},
	select		: function() { // a simple, single element CSS selector (handles unlimited number of selector strings)
		if (!SI.hasRequired) { return; };
		var selected = [];
		
		var parser = function(selector,parents) {
			var selected = [];
			// Establish our actual selector and the remaindered selector to pass to the recursive call
			var remainder = '';
			var pos		= selector.indexOf(' ');
			if (pos!=-1) { 
				remainder	= selector.substring(pos+1,selector.length);
				selector	= selector.substring(0,pos); 
				};
			//SI.Debug.output('S: '+selector+' r['+remainder+']');
			for (var i=0; i<parents.length; i++) {
				if (selector.indexOf('#')!=-1) { 
					selected[selected.length] = document.getElementById(selector.replace(/^([^#]*#)/,'')); 
					}
				else {
					var useClassName = false,elem,className;
					if (selector.indexOf('.')!=-1) {
						useClassName = true;
						selectees = selector.split('.');
						elem = (selectees[0]!='')?selectees[0]:'*';
						className = selectees[1];
						}
					else {
						elem = selector;
						};
					var elems = parents[i].getElementsByTagName(elem);
					for (var j=0; j<elems.length; j++) {
						var re = new RegExp('^('+elems[j].className.replace(/ /g,'|')+')$');
						if (useClassName && className.search(re)==-1) { continue; };
						selected[selected.length] = elems[j];
						};
					};
				};
			if (remainder=='') { return selected; }
			else { return parser(remainder,selected); };
			};
	
		// Make sure we haven't been passed another array (arguments from another function)
 		var args = (arguments.length===1 && typeof arguments[0]!='string')?arguments[0]:arguments;
		for (var i=0; i<args.length; i++) {
			selected = selected.concat(((typeof args[i]=='object')?args[i]:parser(args[i],[document])));
			}
		return selected;
		},
	addClass	: function() {
		if (!SI.hasRequired) { return; };
		var txt = arguments[0];
		for (var i=1; i<arguments.length; i++) { 
			// first remove the class so we don't have duplicates
			txt = txt.replace(new RegExp('( '+arguments[i]+'\\b|\\b'+arguments[i]+' |\\b'+arguments[i]+'\\b)'),'');
			txt += ((txt=='')?'':' ')+arguments[i];
			};
		return txt;
		},
	removeClass	: function() {
		if (!SI.hasRequired) { return; };
		var txt = arguments[0];
		for (var i=1; i<arguments.length; i++) { 
			txt = txt.replace(new RegExp('( '+arguments[i]+'\\b|\\b'+arguments[i]+' |\\b'+arguments[i]+'\\b)'),'');
			};
		return txt;
		}
	};

/******************************************************************************
 SI.References module v1.0
 
 add()
 Takes either an element reference or a collection of element references (the 
 result of getElementsByTagName or the childNodes property) and returns an id 
 pointing to the element reference in the heap or an array of ids respectively.
 
 get()
 Takes an integer id or an array of integer ids and returns an element reference
 or an array of element references from the heap respectively.
 ******************************************************************************/
SI.References =
{
	heap		: [],
	add			: function(arg)
	{
		if (typeof arg == 'object' && arg.nodeType)
		{
			var id = this.heap.length
			this.heap[id] = arg;
			return id;
		}
		else if (arg.length)
		{
			var ids = [];
			for (var i = 0; i < arg.length; i++)
			{
				ids[ids.length] = this.add(arg[i]);
			}
			return ids;
		}
	},
	get			: function(arg) // id can be an integer id corresponding to an element in the heap or an array of ids
	{
		if (typeof arg == 'number')
		{
			return this.heap[arg];
		}
		else if (arg.length)
		{
			var elems = [];
			for (var i =0; i < arg.length; i++)
			{
				elems[elems.length] = this.heap[arg[i]];
			}
			return elems;
		}
	},
	onunload	: function()
	{
		this.heap = null;
	}
};

/******************************************************************************
 SI.Clear module v3.0
 
 The Clear module extends the height of an element with the specified className
 to enclose the absolutely positioned elements inside it. This used to house the
 clearFooter function.
 
 Need to:
 - beable to use an overridable list as an alternative to a static class for
   identifying elements to be cleared
 
 ******************************************************************************/
SI.Clear = {
	clear				: 'clear-contents',
	getContainedHeight	: function(e) {
		var oh=[],h=0,c,k; oh[0]=0;
		for (var i=0; i<e.childNodes.length; i++) { var c=e.childNodes[i]; if (c.nodeType==1) { c.style.height = 'auto'; oh[oh.length] = c.offsetHeight+c.offsetTop; };};
		k=oh.length; do { h = (oh[k]>h)?oh[k]:h; } while(--k);
		return h;
		},
	clearContained		: function() {
		var oh=[],h=0;
		var elems = (arguments.length)?arguments:document.getElementsByTagName("*");
		for (var i=elems.length-1; i>0; i--) {
			var e = elems[i];
			if (e.className.indexOf(this.clear)!=-1) {
				e.style.height = this.getContainedHeight(e)+'px';
				SI.Debug.output('Clearing contents of '+e.nodeName+'.'+e.className+'#'+e.id+': '+e.style.height);
				};
			};
		},
	oncssload			: function() { this.clearContained(); },
	onresize			: function() { this.clearContained(); }
	};

/******************************************************************************
 SI.Footer module v1.2 (offshoot from SI.Clear v2.0)
 
 Footer.snap() snaps the element with the specified id to the bottom of the 
 window if the page content doesn't extend below the fold.
 
 Needs to load after SI.Clear
 v1.1 : Changed Footer.clear() to Footer.snap()
 v1.2 : Reset the height of the element above the footer before performing comparisons
 
 ******************************************************************************/
SI.Footer = {
	footer			: {id:'nav-bottom'},
	prevElem		: function(e) {
		if (!e.previousSibling) { return 0; };
		
		if (e.previousSibling.nodeType=='1') { return e.previousSibling; }
		else if (e.previousSibling.nodeType=='3') { return this.prevElem(e.previousSibling); };
		},
	nextElem		: function(e) {
		if (!e.nextSibling) { return 0; };
		
		if (e.nextSibling.nodeType=='1') { return e.nextSibling; }
		else if (e.nextSibling.nodeType=='3') { return this.nextElem(e.nextSibling); };
		},
	snap			: function() {
		var d=document,w=window,dE=d.documentElement,dB=d.body;
		if (!dB.offsetHeight || !this.footer.e) { return; }
		
		var winHeight = (typeof(w.innerHeight)=='number')?w.innerHeight:(dE&&dE.clientHeight)?dE.clientHeight:(dB&&dB.clientHeight)?dB.clientHeight:0;
		this.above.e.style.height = 'auto';
		if (this.footer.e.offsetTop + this.footer.e.offsetHeight < winHeight && 
			this.above.e.offsetTop + this.above.e.offsetHeight < winHeight) {
		
			this.above.e.style.height = (winHeight-this.above.e.offsetTop-this.footer.e.offsetHeight)+'px';
			SI.Debug.output("Need to bottom out. "+(winHeight-this.above.e.offsetTop-this.footer.e.offsetHeight));
			};
		},
	oncssload		: function() {
		this.footer.e	= document.getElementById(this.footer.id);
		this.above		= {e:this.prevElem(this.footer.e)};
		this.below		= {e:this.nextElem(this.footer.e)};
		if (!this.above.e) { return; };
		
		this.snap();
		},
	onresize		: function() { this.snap(); }
	};


/******************************************************************************
 SI.Images module v1.0
 
 Enables different states on <img> and <input type="image"> tags. 
 States include:
 - over
 - add more later
 
 ******************************************************************************/
SI.Images = {
	preload			: new Array(),
	onbeforeload	: function() {
		var imgs	= document.getElementsByTagName('img');
		var inputs	= document.getElementsByTagName('input');
		var over  	= new Array();
		
		for (var i=0; i<imgs.length; i++) {
			if (imgs[i].src.indexOf('over=')!=-1) { 
				over[over.length] = imgs[i]; 
				};
			};
		for (var j=0; j<inputs.length; j++) {
			if (inputs[j].type=='image' && inputs[j].src.indexOf('over=')!=-1) {
				over[over.length] = inputs[j];
				};
			};
		for (var k=0; img=over[k]; k++) {
			img.defaultsrc	= img.src;
			img.oversrc		= img.src.replace(/[^?\/]*\?(.+)$/i,'') + img.src.replace(/^(.+)over=/i,'');
			img.onmouseover	= function () { this.src = this.oversrc; };
			img.onmouseout	= function () { this.src = this.defaultsrc; };
			
			// preload
			var l = this.preload.length;
			this.preload[l]		= new Image();
			this.preload[l].src	= img.oversrc;
			};
		}
	};


/******************************************************************************
 SI.MovableType module v1.0
 
 Manages the cookies for Movable and prepopulates their associated inputs
 
 ******************************************************************************/
SI.MovableType = {
	oncssload		: function() {
		if (!SI.Cookie) { return; };
		var inputs	= document.getElementsByTagName('input');
		for (var i=0; input=inputs[i]; i++) {	
			// Prepopulate inputs
			if (input.type=='text') {
				if (SI.Cookie.get('mtcmtauth')||SI.Cookie.get('mtcmtmail')||SI.Cookie.get('mtcmthome')) {
					if (input.id=='author')	{ input.value=SI.Cookie.get('mtcmtauth'); }
					if (input.id=='email')	{ input.value=SI.Cookie.get('mtcmtmail'); }
					if (input.id=='url')	{ input.value=(SI.Cookie.get('mtcmthome'))?SI.Cookie.get('mtcmthome'):'http://'; }
					}
				}
			if (input.id=='search') {
				input.defaultValue = input.value;
				SI.Debug.output('Default value for "'+input.id+'" is "'+input.defaultValue+'"');
				
				input.onfocus = function() {
					if (this.value==this.defaultValue) {
						this.value = '';
						}
					}
				input.onblur = function() {
					if (SI.Forms.validate.empty(this.value)) {
						this.value = this.defaultValue;
						}
					}
				}
			if (input.form.id=='form-comment') {
				if (input.id=='author') { 
					// Activate Live Preview
					input.onkeyup = input.onchange = function() { 
						document.getElementById('preview-author').innerHTML=(this.value!='')?this.value:'Your';
						}
					textarea = document.getElementById('text');
					textarea.onfocus = function() {
						SI.Debug.output('Focused');
						if (!textarea.form.unlocked) {
							textarea.form.unlocked = window.setTimeout('SI.MovableType.unlock()',7*1000);
							}
						};
					textarea.onkeyup = function() {
						document.getElementById('preview-comment').innerHTML=SI.MovableType.tmpMarkdownWithSmartyPants(this.value);
						SI.onresize();
						};
					}
				if (input.id=='bakecookie') {
					var label = input.parentNode;
					label.onclick = function() {
						this.checkbox.checked = !(this.checkbox.checked);
						this.className = (this.checkbox.checked)?SI.CSS.addClass(this.className,'checked'):SI.CSS.removeClass(this.className,'checked');
						if (this.checkbox.checked) {
							SI.Cookie.set('mtcmtauth',document.getElementById('author').value);
							SI.Cookie.set('mtcmtmail',document.getElementById('email').value);
							SI.Cookie.set('mtcmthome',document.getElementById('url').value);
							}
						else {
							SI.Cookie.toss('mtcmtauth');
							SI.Cookie.toss('mtcmtmail');
							SI.Cookie.toss('mtcmthome');
							}
						}
					}
				}
			}
		},
	onsubmit	: function(form) {
		SI.Debug.output('SI.MovableType received submit request from '+form.id);
		if (form.id=='form-comment') {
			SI.Debug.output('Found Moveable Type form: '+form.id);
			if (document.getElementById('bakecookie').checked) {
				SI.Cookie.set('mtcmtauth',document.getElementById('author').value);
				SI.Cookie.set('mtcmtmail',document.getElementById('email').value);
				SI.Cookie.set('mtcmthome',document.getElementById('url').value);
				}
			}
		},
	unlock		: function() {
		var form = document.getElementById('form-comment');
		form.action = '/mt/com.ment';
		SI.Debug.output('SI.MovableType unlocked: '+form.action);
		},
	tmpMarkdownWithSmartyPants : function(txt) {
		txt = txt.replace(/`([^`]+)`/g,'<code>'+'$1'+'<'+'/code>');
		txt = txt.replace(/&/g,'&amp;');
		txt = txt.replace(/&(amp;)+/g,'&amp;');
		txt = txt.replace(/-{3}/g, '&#8211;');
		txt = txt.replace(/-{2}/g,'&#8212;');
		txt = txt.replace(/\.{3}/g,'&#8230;');
		txt = txt.replace(/\"(.*[^\"])\"/g,'&#8220;$1&#8221;');
		txt = txt.replace(/(\*|_){2}([^*_]+)(\*|_){2}/g,'<strong>'+'$2'+'<'+'/strong>');
		txt = txt.replace(/(\*|_)([^*_]+)(\*|_)/g,'<em>'+'$2'+'<'+'/em>');
		txt = '<p>'+txt.replace(/(\r\n|\n)/g,'<br />').replace(/(<br \/>){2,}/gi,'<'+'/p><p>')+'<'+'/p>';
		return txt;
		}
	};

/******************************************************************************
 SI.Feeds module v1.0
 
 
 
 ******************************************************************************/
SI.Feeds = {
	baseFeed	: '',
	yourFeed	: '',
	oncssload	: function() {
		this.form		= document.getElementById('form-feed');
		if (!this.form) { return; }
		
		this.form.onclick = function() {
			SI.Feeds.rebuild();
			}
		this.inputs		= this.form.getElementsByTagName('input');
		this.feedInput	= document.getElementById('feed-url');
		this.baseFeed	= this.feedInput.value;
		},
	rebuild		: function() {
		var categories	= [];
		var comments	= 0;
		for (var i=0; input=this.inputs[i]; i++) {
			if (input.type=='checkbox' && !input.checked) {
				categories[categories.length] = input.value;
				}
			else if (input.type=='radio' && input.checked) {
				comments = input.value;
				};
			};
		this.yourFeed = this.baseFeed+'?'+((categories.length!=0)?'excluding='+categories.join(','):'')+((categories.length!=0 && comments!=0)?'&':'')+((comments!=0)?'comments='+comments:'');
		this.feedInput.value = this.yourFeed;
		document.getElementById('feed-url-link').href = this.yourFeed;
		SI.Debug.output('SI.Feeds rebuilt: '+this.yourFeed,1);
		}
	};

/******************************************************************************
 SI.Forms module v1.1
 
 v1.1 : Adds radio button behaviors
 
 ******************************************************************************/
SI.Forms = {
	oncssload		: function() {
		var inputs	= document.getElementsByTagName('input');
		for (var i=0; input=inputs[i]; i++) {	
			// Activate custom checkboxes
			if (input.type=='checkbox' && input.parentNode.nodeName=='LABEL') {
				var label = input.parentNode;
				label.checkbox = input;
				if (label.checkbox.checked) { 
					label.className = SI.CSS.addClass(label.className,'checked'); 
					};
				
				if ((typeof label.onclick)!='function') {
					label.onclick = function() {
						SI.Debug.output('Click');
						this.checkbox.checked = !(this.checkbox.checked);
						this.className = (this.checkbox.checked)?SI.CSS.addClass(this.className,'checked'):SI.CSS.removeClass(this.className,'checked');
						
						if (this.id=='checkbox-increase-contrast') {
							var html = document.getElementsByTagName('html')[0];
							if (this.checkbox.checked) {
								html.className = SI.CSS.addClass(html.className,'increase-contrast');
								SI.Cookie.set('Contrast',1);
								}
							else {
								html.className = SI.CSS.removeClass(html.className,'increase-contrast');
								SI.Cookie.toss('Contrast');
								};
							// force resize event because I'm changing an element that SI.Resize can't detect
							SI.onresize();
							};
						};
					};
				}
			else if (input.type=='radio' && input.parentNode.nodeName=='LABEL') {
				var label = input.parentNode;
				label.radio = input;
				if (label.radio.checked) { 
					label.className = SI.CSS.addClass(label.className,'checked'); 
					};
				
				if ((typeof label.onclick)!='function') {
					label.onclick = function() {
						// reset all
						var inputs	= document.getElementsByTagName('input');
						for (var i=0; input=inputs[i]; i++) {
							if (input.type=='radio') { // && input.name==this.name) {
								input.checked = false;
								input.parentNode.className = SI.CSS.removeClass(input.parentNode.className,'checked');
								}
							}
						
						this.radio.checked = true;
						this.className = SI.CSS.addClass(this.className,'checked');
						};
					};
				};
			};
		},
	onsubmit	: function(form) {
		SI.Debug.output('SI.Form received submit request from '+form.id);
		if (form.innerHTML.match(/require/i)) {
			SI.Debug.output(form.id+' requires validation');
			return this.validate.form(form);
			};
		},
	validate	: {
		form	: function(form) {
			SI.Debug.output('Validating '+form.id);
			form.errors = new Array();
			var labels	= form.getElementsByTagName('label');
			for (var i=0; label=labels[i]; i++) {
				if (label.innerHTML.match(/require/i)) {
					var labelName = label.innerHTML.replace(/:.*$/,'');
					var input = document.getElementById(label.htmlFor);
					if (input && this.empty(input.value)) {
						form.errors[form.errors.length] = 'Please enter a value in the required field: '+labelName;
						}
					else if (input && label.innerHTML.match(/email/i) && !this.email(input.value)) {
						form.errors[form.errors.length] = 'Your email address doesn&#8217;t appear to valid. Please double-check it.'
						};
					};
				};
			if (!form.errors.length) {
				this.clearErrors(form);
				return true;
				}
			else {
				var failed	= ['The form could not be submitted for the following reasons:'];
				form.errors	= failed.concat(form.errors);
				this.displayErrors(form);
				return false;
				};
			
			SI.Debug.output(form.id+' validated');
			return false;
			},
		displayErrors	: function(form) {
			SI.Debug.output('Reporting errors in '+form.id);
			if (!document.getElementById(form.id+'-errors')) {
				var errors			= document.createElement('div');
				errors.id			= form.id+'-errors';
				errors.className	= 'errors';
				}
			else {
				var errors			= document.getElementById(form.id+'-errors');
				};
			
			var errorMessage = '<p>'+form.errors[0]+'</p><ul>';
			for (var i=1; i<form.errors.length; i++) {
				errorMessage += '<li>'+form.errors[i]+'</li>';
				};
			errorMessage	+= '</ul>';
			errors.innerHTML = errorMessage;
			form.parentNode.insertBefore(errors,form);
			SI.onresize();
			},
		clearErrors : function(form) {
			if (document.getElementById(form.id+'-errors')) {
				var errors = document.getElementById(form.id+'-errors');
				errors.parentNode.removeChild(errors);
				SI.onresize();
				};
			},
		email	: function(email) { return (email.search(/^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/) != -1)?true:false; },
		empty	: function(value) { var empty = /^\s*$/; return empty.test(value); }
		}
	};


/******************************************************************************
 SI.Navigation module v2.0
 
 Shares a single, slide-out navigation between to elements
 
 ******************************************************************************/
SI.Navigation = {
	content		: {id:'nav-main'},
	top			: {id:'nav-top',state:0},
	bottom		: {id:'nav-bottom',state:1}, // state is 1 because the navigation defaults to display block
	revealInit	: false,
	revealLoop	: false,
	revealId	: null,
	getScrollTop	: function() {
		if (document.all) { return (document.documentElement.scrollTop) ? document.documentElement.scrollTop : document.body.scrollTop; }
		else { return window.pageYOffset; }
		},
	toggle		: function(navElem,e) {
		if (!document.removeChild || !document.appendChild) return;
		SI.Debug.output('Navigation activated: '+navElem.id);
		
//		e.blur();
		
		this.top.e.parentNode.className		= this.top.e.parentNode.className.replace(/ open/,'');
		this.bottom.e.parentNode.className	= this.bottom.e.parentNode.className.replace(/ open/,'');
		
		if (navElem.state) {
			navElem.state = 0;
			}
		else {
			navElem.e.appendChild(this.content.e);
			navElem.state = 1;
			navElem.opp.state = 0;
			navElem.opp.e.style.height = '3px';
			navElem.e.parentNode.className += ' open';
			}
		// Now grow the container
		this.reveal(navElem);
		},
	reveal		: function(navElem) {
		if(this.revealLoop){
			clearInterval(this.revealId);
			this.revealLoop = false;
			this.revealId = null;
			}
		this.revealTo(navElem.id.replace(/^nav-/,''),(navElem.state)?this.content.e.offsetHeight:0);
		},
	revealTo	: function(navRef,h) {
		var navElem = eval('this.'+navRef);
		if (h==0) { h=3; }
		if (this.revealLoop) {
			var c = navElem.e.offsetHeight
			if (Math.abs(c-h) <=1) {
				SI.Debug.output('Navigation '+((!navElem.state)?'collapsed':'expanded')+': '+navRef+' at '+h+'px');
				navElem.e.style.height = h+'px';
				if (!navElem.state) { this.content.e = this.content.e.parentNode.removeChild(this.content.e); }
				clearInterval(this.revealId);
				this.revealLoop = false;
				this.revealId = null;
				if (!this.revealInit) { this.revealInit = true; }
				}
			else {
				navElem.e.style.height = (c+(h-c)/2)+'px';
				if (navElem.e.offsetTop!=0 && this.revealInit) { window.scrollTo(0,this.getScrollTop()+h); }
				}
			}
		else {
			this.revealId = setInterval("SI.Navigation.revealTo('"+navRef+"',"+h+")",100);
			this.revealLoop = true;
			}
		if (SI.Footer) { SI.Footer.snap(); };
		},
	onbeforeload	: function() {
		// Assemble our container element references
		this.content.e	= document.getElementById(this.content.id);
		this.top.e		= document.getElementById(this.top.id).getElementsByTagName('div')[0];
		this.bottom.e	= document.getElementById(this.bottom.id).getElementsByTagName('div')[1];
		
		// Assemble our link references
		this.top.a		= document.getElementById(this.top.id).getElementsByTagName('a')[0];
		this.bottom.a	= document.getElementById(this.bottom.id).getElementsByTagName('a')[0];
		
		// Add a reference to the opposite element
		this.top.opp	= this.bottom;
		this.bottom.opp	= this.top;
		
		// Attach event handlers to links
		this.top.a.onclick		= function() { SI.Navigation.toggle(SI.Navigation.top,this); return false; }
//		this.bottom.a.onclick	= function() { SI.Navigation.toggle(SI.Navigation.bottom,this); return false; }
		
		// Testing
		/** /
		this.top.a.onmouseover		= function() { SI.Navigation.toggle(SI.Navigation.top,this); return false; }
		this.bottom.a.onmouseover	= function() { SI.Navigation.toggle(SI.Navigation.bottom,this); return false; }
		/**/
		
		if (this.content.e && this.top.e && this.bottom.e) {
			this.toggle(this.bottom,this.bottom.a);
			};
		},
	onresize	: function() {
		if (this.revealInit) {
			if (this.top.state) { this.reveal(this.top); }
			else if (this.bottom.state) { this.reveal(this.bottom); }
			}
		}
	};


/******************************************************************************
 SI.Tabs module v1.0
 
 To do
 - Set a cookie so that tab choice is persistent
 
 ******************************************************************************/
SI.Tabs = {
	className 		: 'tabs',
	container		: 'div',
	onbeforeload	: function() {
		var elems	= document.getElementsByTagName(this.container);
		for (var i=0; i<elems.length; i++) {
			var e = elems[i];
			if (e.className==this.className) {
				var tabs = e.getElementsByTagName('a');
				for (var j=0; j<tabs.length; j++) {
					var lnk		= tabs[j];
					lnk.tabs	= tabs;
					lnk.tab		= document.getElementById(lnk.href.replace(/^([^#]*#)/,''));
					// Hide inactive links
					if (lnk.className!='active') { lnk.tab.style.display = 'none'; }
					else {
						SI.Debug.output('Tabs initialized, "'+lnk.tab.id+'" is active.');
						SI.Tabs.autofocus(lnk.tab);
						};
					lnk.onclick = function() {
						SI.Debug.output('Tab "'+this.tab.id+'" is active.');
						// disable all tabs
						for (var i=0; i<this.tabs.length; i++) {
							var lnk = this.tabs[i];
							lnk.className = '';
							lnk.tab.style.display = 'none';
							};
						this.className = 'active';
						this.tab.style.display = 'block';
						this.blur();
						SI.Tabs.autofocus(this.tab);
						SI.onresize();
						return false;
						};
					};
				};
			};
		},
	autofocus		: function(e) {
		var inputs = e.getElementsByTagName('input');
		for (var i=0; i<inputs.length; i++) {
			var input = inputs[i];
			if (input.type=='text') {
				SI.Debug.output('Autofocusing '+input.id);
				input.focus();
				input.select();
				break;
				};
			};
		}
	};


/******************************************************************************
 SI.Folders module v1.0
 
 v1.1 : Folders now default to `open` class
 
 ******************************************************************************/
SI.Folders = {
	className 		: 'folder',
	cookie			: '',
	onbeforeload	: function() {
		var elems	= document.getElementsByTagName('dl');
		
		this.cookie = SI.Cookie.get('Folders');
		SI.Debug.output('Initializing Folders: '+this.cookie);
		
		var c = 0;
		tmpCookie = '';
		for (var i=0; e=elems[i]; i++) {
			if (e.className==this.className) {
				var folder = e.getElementsByTagName('dt')[0];
				var content = e.getElementsByTagName('dd')[0];
				
				folder.style.cursor = 'pointer';
				folder.content = content;
				folder.index = c;
				folder.open  = (this.cookie.charAt(c)=='1')?true:false;
				folder.className = (folder.open)?'open':'';
				
				if (!folder.open) {
					SI.Debug.output('Collapsing Folder '+c+': '+folder.innerHTML);
					content.style.display = 'none';
					};
				
				folder.onclick = function() { SI.Folders.toggleFolder(this); };
				c++;
				};
			};
		},
	toggleFolder	: function(e) {
		SI.Debug.output(((e.open)?'Collapsing':'Expanding')+': '+e.innerHTML);
		
		e.open = !e.open;
		e.content.style.display = (e.open)?'block':'none';
		e.className = (e.open)?'open':'';
		
		var tmpCookie = this.cookie;
		tmpCookie = tmpCookie.substring(0,e.index)+((e.open)?'1':'0')+tmpCookie.substring(e.index+1);
		this.cookie = tmpCookie;
		SI.Cookie.set('Folders',this.cookie);
		SI.onresize();
		}
	};
	
	
/******************************************************************************
 SI.Cookie module v1.0
 
 ******************************************************************************/
SI.Cookie = {
	domain	: location.hostname.replace(/^www\./,''),
	set		: function(name,value) {
		SI.Debug.output('Setting cookie "SI-'+name+'" to "'+value+'" for '+this.domain);
		
		var expires = new Date();
		var base 	= new Date(0);
		var diff 	= base.getTime();
		if (diff>0) { expires.setTime(expires.getTime()-diff); };
		expires.setTime(expires.getTime() + 365 * 24 * 60 * 60 * 1000);
		
		document.cookie = "SI-" + name + "=" + value + ";expires=" + expires.toGMTString() + ";path=/;domain=" + this.domain;
		},
	get		: function(name) {
		var p = "SI-" + name+"="; 
		var c=document.cookie;
		var i=c.indexOf(p);
		if (i==-1) { return ''; };
		var e=c.indexOf(";",i+p.length);
		if (e==-1) {e = c.length; };
		return unescape(c.substring(i+p.length,e));
		},
	toss	: function(name) {
		SI.Debug.output('Tossing cookie "SI-'+name+'"');
		document.cookie = "SI-" + name + "=;expires=Thu, 01-Jan-70 00:00:01 GMT;path=/;domain=" + this.domain;
		}
	};

/******************************************************************************
 SI.IFR module v1.1
 
 v1.1 : escaped text before adding to flashvar when double quotes are detected
 
 ******************************************************************************/
SI.IFR = {
	replaced		: 0,
	replace			: function(selector,swf,size,lineheight,color,altcolor,bgcolor,uppercase,padding) {
		var d = document;
		
		if (!SI.hasFlash) return;
		
		var elems = SI.CSS.select(selector);
		for (var i=0; i<elems.length; i++) {
			e = elems[i];
			
			var orig	= e.innerHTML.normalize();
			var txt 	= new Array();
			var fv		= '';
			for (var j=0; j<e.childNodes.length; j++) {
				var c = e.childNodes[j];
				switch (c.nodeType) {
					case 3:
						txt[txt.length] = c.nodeValue.normalize();
						break;
					case 1:
						txt[txt.length] = c.innerHTML.normalize();
						break;
					}
				}
			
			var c = d.createElement('div');
			
			var nw = nh = 0;
			if (padding.length==1) {
				nw = nh = padding[0] * 2;
				}
			else if (padding.length==2) {
				nh = padding[0] * 2;
				nw = padding[1] * 2;
				}
			else if (padding.length==3) {
				nh = padding[0] + padding[2];
				nw = padding[1] * 2;
				}
			else if (padding.length==4) {
				nh = padding[0] + padding[2];
				nw = padding[1] + padding[3];
				}
			
			w = e.offsetWidth-nw;
			h = e.offsetHeight-nh;
			c.className = 'replaced-'+e.nodeName.toLowerCase();
			c.id = 'SI_replaced'+this.replaced++;
			e.parentNode.replaceChild(c,e);
			
			for (var k=0; k<txt.length; k++) { 
				if (txt[k].indexOf('"')!=-1) { txt[k] = escape(txt[k]); }
				fv += 'txt'+(k+1)+'='+txt[k]+'&';
				}
			fv += 't='+ txt.length+'&w='+w+'&h='+h+'&id='+c.id+'&s='+size+'&l='+lineheight+'&c='+color+'&ac='+altcolor+'&uc='+uppercase;
			
			var swfHTML;
			swfHTML  = '<object class="mlIFRobject" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0" width="'+w+'" height="'+h+'">\n';
			swfHTML += '	<param name="movie" value="'+swf+'" />\n';
			swfHTML += '	<param name="flashvars" value="'+fv+'" />\n';
			swfHTML += '	<param name="bgcolor" value="'+bgcolor+'" />\n';
			swfHTML += '	<param name="wmode" value="opaque" />\n';
			swfHTML += '	<embed class="mlIFRobject" src="'+swf+'" flashvars="'+fv+'" width="'+w+'" height="'+h+'" bgcolor="'+bgcolor+'" wmode="opaque" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />\n';
			swfHTML += '<'+'/object>\n';
			swfHTML += '<'+e.nodeName.toLowerCase()+((e.id)?' id="'+e.id+'"':'')+' class="'+((e.className)?e.className+' ':'')+'replaced">'+orig+'<'+'/'+e.nodeName.toLowerCase()+'>\n';
			c.innerHTML = swfHTML;
			txt='';
			}
		},
	refresh			: function() { document.body.innerHTML+=''; },
	oncssload		: function() {
		this.replace('h1.headline','/assets/swf/default/din-light.swf',20,15,'666666','AB6666','FFFFFF',true,[0]);
		this.replace('h1.section','/assets/swf/default/din-light.swf',20,15,'AB6666','','FFFFFF',true,[0]);
		this.replace('h2.posted-date','/assets/swf/default/din-medium.swf',10,12,'666666','999999','FFFFFF',true,[0]);
		
		/** /this.replace('.comments-count p','/assets/swf/default/din-medium.swf',10,12,'AB6666','666666','FFFFFF',true,[0]);
		this.replace('.intro p','/assets/swf/default/din-medium.swf',10,12,'AB6666','','FFFFFF',true,[0]);
		this.replace('.comment dt span.author','/assets/swf/default/din-medium.swf',10,12,'666666','AB6666','FFFFFF',true,[0]);
		this.replace('.comment dt span.date','/assets/swf/default/si7-custom.swf',8,8,'999999','','FFFFFF',true,[0]);/**/
		}
	};

/******************************************************************************
 SI.IFR Support functions
 
 Written by Mark Wubben http://www.novemberborn.net/
 
 ******************************************************************************/
String.prototype.normalize = function(){ return this.replace(/\s+/g, " "); };
if(Array.prototype.push == null){ Array.prototype.push = function(){ for(var i = 0; i < arguments.length; i++){ this[this.length] = arguments[i]; }; return this.length; };};

/******************************************************************************
 window.onload/onresize()
 
 This should only ever require SI.onload() which in turn initializes all modules
 that require it.
 
 ******************************************************************************/
window.onload	= function() { SI.onload(); };
window.onresize	= function() { SI.onresize(); };
/**/