String.prototype.trim = function(){ return this.replace(/^\s+|\s+$/g,'') }
String.prototype.unescHtml = function(){ var i,e={'&lt;':'<','&gt;':'>','&amp;':'&','&quot;':'"'},t=this; for(i in e) t=t.replace(new RegExp(i,'g'),e[i]); return t }

function loadTags(t) { tags = t }

Fold = {
	folded : {},
	go : function(){
		if(!document.getElementsByTagName || !document.childNodes) return
		var fold,label,newfold,newlabel,i
		fold = Cookies.get('_fold')
		if(fold) { fold = fold.split(' '); for(i in fold) { this.folded[fold[i]] = 1 } }
		var folds = $c('fold',document,'li')
		this.ffhack() //weird spacing bug in ff
		for(fold in folds) { fold = folds[fold]
			label = $c('label',fold)[0]
			if(label) {
				label.label = $tag('span',label).innerHTML.replace(/[ ;]+/g,'')
				this.makeArrow(label,'d');

				newfold = document.createElement('li')
				newfold.className = fold.className; swapClass(newfold,'fold','grey')

				newlabel = label.cloneNode(true)
				$tag('img',newlabel).src="/static/img/arrow.r.gif"

				newfold.appendChild(newlabel)
				fold.parentNode.insertBefore(newfold,fold)

				if(this.folded[label.label]) { newfold.style.display = 'block'; fold.style.display = 'none' }
				else newfold.style.display = 'none'

				label.style.cursor = newlabel.style.cursor = 'pointer'
				label.onclick = this.makeToggle(newfold, fold, label.label, true)
				newlabel.onclick = this.makeToggle(fold, newfold, label.label)
	}}},
	makeArrow : function(label,i){
		var img = document.createElement('img')
		img.src = "/static/img/arrow."+i+".gif"; img.width = img.height = 8;
		if(i == 'r') img.className = 'grey'
		addClass(label,'arrow')
		label.insertBefore(img, label.firstChild)
	},
	makeToggle : function(show,hide,cookieKey,cookieSet){ return (function(){
		var cookie='',f
		show.style.display = 'block'; hide.style.display = 'none'
		if(cookieSet) Fold.folded[cookieKey] = 1
		else delete Fold.folded[cookieKey]
		for(f in Fold.folded) cookie += f + ' '; Cookies.set('_fold', cookie, 30)
	})},
	ffhack : function() { var u=$c('bundles',document,'ul'),i
		for(i in u) {i=u[i]; var b=document.createElement('li'); b.innerHTML='&nbsp;'; b.className='bundle ffhack'; i.insertBefore(b,i.firstChild) }
}}

Cookies = {
	set : function(name,value,days){ var expires = '', days = days||30
		var date = new Date(); date.setTime(date.getTime()+(days*24*60*60*1000)); expires = "; expires="+date.toGMTString()
		document.cookie = name+"="+value+expires+"; path=/"
	},
	get : function(name){
		var ca = document.cookie.split(';'),i,c; name += '='
		for(i=0; i < ca.length; i++) {
			c = ca[i];
			while (c.charAt(0)==' ') c = c.substring(1,c.length)
			if (c.indexOf(name) == 0) return c.substring(name.length,c.length)
		}
		return null
}}

Mp3 = {
	playimg: null,
	player: null,
	go: function() {
		var all = $c('mp3', document, 'a')
		for (var i = 0, a; a = all[i]; i++) {
			var img = document.createElement('img')
			img.src = '/static/img/mp3/play.gif'; img.title = 'listen'
			img.className = 'player'
			img.height = img.width = 12
			img.onclick = Mp3.makeToggle(img, a.href)
			a.parentNode.insertBefore(img, a)
	}},
	toggle: function(img, url) {
		if (Mp3.playimg == img) Mp3.destroy()
		else {
			if (Mp3.playimg) Mp3.destroy()
			img.src = '/static/img/mp3/stop.gif'; Mp3.playimg = img;
			Mp3.player = document.createElement('span')
			Mp3.player.innerHTML = '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"' +
			'codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0"' +
			'width="50" height="15" align="middle" class="player">' +
			'<param name="allowScriptAccess" value="sameDomain" />' +
			'<param name="flashVars" value="theLink='+url+'" />' +
			'<param name="movie" value="/static/swf/mp3.swf" /><param name="quality" value="high" />' +
			'<param name="bgcolor" value="#ffffff" />' +
			'<embed src="/static/swf/mp3.swf" flashVars="theLink='+url+'"'+
			'quality="high" bgcolor="#ffffff" width="50" height="15" name="player"' +
			'align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash"' +
			' pluginspage="http://www.macromedia.com/go/getflashplayer" class="player" /></object>'
			img.parentNode.insertBefore(Mp3.player, img.nextSibling)
	}},
	destroy: function() {
		Mp3.playimg.src = '/static/img/mp3/play.gif'; Mp3.playimg = null
		Mp3.player.removeChild(Mp3.player.firstChild); Mp3.player.parentNode.removeChild(Mp3.player); Mp3.player = null
	},
	makeToggle: function(img, url) { return function(){ Mp3.toggle(img, url) }}
}

Crumb = {
	go: function(root){
		var p = $id('crumb'), o = document.createElement('input')
		var tag = p.innerHTML.unescHtml()
		o.className = 'crumb'
		o.originalValue = o.value = tag
		o.root = root || '/tag/'
		o.onblur = Crumb.blur; o.onfocus = Crumb.focus
		o.onmouseover = Crumb.mouseover; o.onmouseout = Crumb.mouseout
		o.onkeyup = o.onkeypress = Crumb.keyhandler
		p.innerHTML = ''; p.appendChild(o)
		resizeToText(o, tag, 40)
	},
	mouseover: function() { addClass(this, 'crumb-focus') },
	mouseout: function() { if(!this.focused) rmClass(this, 'crumb-focus') },
	focus: function() { this.focused = true; addClass(this, 'crumb-focus') },
	blur: function() {
		if (this.submitting) return false
		this.focused = false
		this.value = this.originalValue
		rmClass(this, 'crumb-focus')
		resizeToText(this, this.value, 40)
	},
	keyhandler: function(e) { e = e||window.event
		if (e.type == 'keypress' && e.keyCode == 13) {
			var tag = this.value.replace(/ +/g, '+')
			if (tag) {
				this.submitting = true
				location.href = this.root + tag
		}}
		resizeToText(this, this.value, 40)
}}

function footer() {
	var h = windowHeight(), footer = $id('footer'), bottom = getY($id('bottom')), sidebar = $id('sidebar')
	var fh = footer.clientHeight || footer.offsetHeight // todo: why does IE report 0 for clientHeight?
	if (bottom != 0) {
		if (bottom < h - fh) footer.style.marginTop = ((h - fh)-bottom-3)+'px'
		else footer.style.marginTop = 0
	}
	footer.parentNode.style.visibility = 'visible'
}

function addEngine()
{
	if ((typeof window.sidebar == "object") &&
		(typeof window.sidebar.addSearchEngine == "function")) {
			window.sidebar.addSearchEngine(
				"http://del.icio.us/search/delicious.src",
				"http://del.icio.us/static/img/search/delicious.gif",
				"delicious",
				'Web' );
	}
}

// the delete post confirmation
function rmPostAddEvent() {
	var all = $c('rm', $tags('ol'),'a')
	for(var i = 0, o; o = all[i]; i++) o.onclick = function(){ return rmPost(this) }
}
function rmPost(o) {
	o.style.display = 'none'
	var s = document.createElement('span'); s.o = o
	s.innerHTML = '<span class="important">delete this post?</span> <a href="'+o.href+'">yes</a> / <a href="'+o.href.replace(/(\?|&)delete=[^&]*&?/,'$1')+'" onclick="this.parentNode.o.style.display=\'inline\';this.parentNode.parentNode.removeChild(this.parentNode);return false">no</a>'
	o.parentNode.insertBefore(s, o)
	return false
}

// get previous/next non-text node
function previousElement(o) {
	if(o.previousSibling) { while (o.previousSibling.nodeType != 1) o = o.previousSibling; return o.previousSibling }
	else return false
}
function nextElement(o) {
	if(o.nextSibling) { while (o.nextSibling.nodeType != 1) o = o.nextSibling; return o.nextSibling }
	else return false
}

// styling functions
function isA(o,klass){ if(!o.className) return false; return new RegExp('\\b'+klass+'\\b').test(o.className) }
function addClass(o,klass){ if(!isA(o,klass)) o.className += ' ' + klass }
function rmClass(o,klass){ o.className = o.className.replace(new RegExp('\\s*\\b'+klass+'\\b'),'') }
function swapClass(o,klass,klass2){ var swap = isA(o,klass) ? [klass,klass2] : [klass2,klass]; rmClass(o,swap[0]); addClass(o,swap[1]) }
function getStyle(o,s) {
	if (document.defaultView && document.defaultView.getComputedStyle) return document.defaultView.getComputedStyle(o,null).getPropertyValue(s)
	else if (o.currentStyle) { return o.currentStyle[s.replace(/-([^-])/g, function(a,b){return b.toUpperCase()})] }
}
// shorter names for grabbing stuff
function $id(id){ return document.getElementById(id) }
function $tags(t,o){ o=o||document; return o.getElementsByTagName(t) }
function $tag(t,o,i) { o=o||document; return o.getElementsByTagName(t)[i||0] }
// get elements by class name, eg $c('post', document, 'li')
function $c(c,o,t) { o=o||document;
	if (!o.length) o = [o]
	else if(o.length == 1 && !o[0]) o = [o] // opera, you're weird
	var elements = []
	for(var i = 0, e; e = o[i]; i++) {
		if(e.getElementsByTagName) {
			var children = e.getElementsByTagName(t || '*')
			for (var j = 0, child; child = children[j]; j++) if(isA(child,c)) elements.push(child)
	}}
	return elements
}

function extend(dest, src) {
	for (var p in src) dest[p] = src[p]
	return dest
}

// get mouse pointer position
function pointerX(e) { return e.pageX || (e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft)) }
function pointerY(e) { return e.pageY || (e.clientY + (document.documentElement.scrollTop || document.body.scrollTop)) }

// get window size
function windowHeight() { return self.innerHeight || document.documentElement.clientHeight || document.body.clientHeight || 0 }
function windowWidth() { return self.innerWidth || document.documentElement.clientWidth || document.body.clientWidth || 0 }

// get pixel position of an object
function getY(o){ var y = 0
	if (o.offsetParent) while (o.offsetParent) { y += o.offsetTop; o = o.offsetParent }
	return y
}
function getX(o){ var x = 0
	if (o.offsetParent) while (o.offsetParent) { x += o.offsetLeft; o = o.offsetParent }
	return x
}

// form stuff
function getRadioValue(o) {
	for(var i = 0, r; r = o[i]; i++) if (r.checked && r.value) return r.value
	return false
}

// todo: make less crap
function resizeToText(o, text, margin) {
	margin = margin || 0
	var c = $id(o.id + '-copy')
	if (!c) { makeResizeThing(o); c = $id(o.id + '-copy') }
	var esc = {'<':'[','>':']',' ':'&nbsp;'}
	for(var i in esc) text=text.replace(new RegExp(i,'g'), esc[i])
	c.innerHTML = text
	o.style.width = c.offsetWidth + margin + 'px'
}
function makeResizeThing(src) {
	var o = document.createElement('div')
	o.style.position = 'absolute'; o.style.top = o.style.left = 0
	o.style.visibility = 'hidden'
	o.style.fontSize = getStyle(src, 'font-size')
	o.style.fontFamily = getStyle(src, 'font-family')
	o.id = src.id + '-copy'
	src.parentNode.appendChild(o)
}

// event functions
function falseFunc(){ return false }
function addLoadEvent(f) { var old = window.onload
	if (typeof old != 'function') window.onload = f
	else { window.onload = function() { old(); f() }}
}

function mailer(oName,oDomain) {
 email="mailto:" + oName + "@" + oDomain;
 window.location=email;
}

addLoadEvent(rmPostAddEvent)

// the following two functions ganked from prototype (see http://prototype.conio.net)
// (c) 2005 Sam Stephenson
var Class = {
	create: function() {
		return function() { this.initialize.apply(this, arguments) }
}}
Function.prototype.bind = function(o) {
	var __method = this
	return function() { return __method.apply(o, arguments) }
}

