var Crumb = {
	go: function(root){
		var p = $id('crumb')
		var tag = p.innerHTML.unescHtml();
        var f = create('form', { method:'get', action:'/', onsubmit: function(){ return false; } });
		var r = create('input', {type:'hidden', name: 'root', value: root});
		var o = create('input', {name: 'crumb', css: 'crumb', originalValue: tag, value: tag, root: root || '/',
			onblur: Crumb.blur, onfocus: Crumb.focus, onmouseover: Crumb.mouseover, onmouseout: Crumb.mouseout,
			onkeyup: Crumb.keyhandler, onkeypress: Crumb.keyhandler});
        f.appendChild(r);
        f.appendChild(o); f.className = 'crumbform';
		p.innerHTML = ''; p.appendChild(f)
		Crumb.sizer = makeTextSize(getTextStyle(o), p)
		o.style.width = getTextSize(tag, Crumb.sizer) + 120 + 'px'
	},
	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')
		this.style.width = getTextSize(this.value, Crumb.sizer) + 120 + 'px'
	},
	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 + encodeURIComponent(tag)
		}}
		this.style.width = getTextSize(this.value, Crumb.sizer) + 90 + 'px'
}}

function extend(dest, src){
	if(!src) return dest
	for(var k in src) dest[k] = src[k]
	return dest
}
function niceExtend(dest, src){
	if(!src) return dest
	if(src.html) { dest.innerHTML = src.html; delete src.html }
	if(src.css) { dest.className = src.css; delete src.css }
	if(src.attr) {
		var s = src.attr
		for(var k in s) dest.setAttribute(k, s[k])
		delete src.attr
	}
	if(src.style) {
		var d = dest.style, s = src.style
		for(var k in s) d[k] = s[k]
		delete src.style
	}
	for(var k in src) dest[k] = src[k]
	return dest
}

function isArray(o) { if(o && typeof o == 'object' && o.constructor == Array) return true; return false }

extend( String.prototype, {
	include: function(t) { return this.indexOf(t) >= 0 ? true : false },
	trim: function(){ return this.replace(/^\s+|\s+$/g,'') },
	splitrim: function(t){ return this.trim().split(new RegExp('\\s*'+t+'\\s*')) },
	encodeTag: function() { return encodeURIComponent(this).replace(/%2F/g, '/') },
	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 },
	escHtml: function(){ var i,e={'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'},t=this; for(i in e) t=t.replace(new RegExp(i,'g'),e[i]); return t },
	escRegExp: function(){ return this.replace(/[\\$*+?()=!|,{}\[\]\.^]/g,'\\$&') }
})

Number.prototype.times = function(f){
	var n = this
	while(n > 0) { f(); n-- }
}

// make a cheep hash from an array
Object.fromArray = function(src, value){
	if(typeof(value) == 'undefined') value = true
	var r = {}, l = src.length
	for (var i = 0; i < l; i++) r[src[i]] = value
	return r
}

// copy an arraylike obj to an actual array
Array.from = function(src){
	var l = src.length, r = []
	for (var i=0; i<l; i++) r[i] = src[i]
	return r
}
// push/collapse. needs a better name
Array.prototype.pushc = function(o){
	if (o === null || typeof(o) == 'undefined') return this
	else if (o.each) o.each( function(i){ this.pushc(i) }.bind(this) )
	else this.push(o)
	return this
}
Array.prototype.each = function(f){
	var l = this.length
	for(var i = 0; i < l; i++) f(this[i], i)
	return this
}
Array.prototype.map = function(f){
	var r = [], l = this.length
	for (var i = 0; i < l; i++) r.push(f(this[i], i))
	return r
}
// map/collapse. needs a better name
Array.prototype.mapc = function(f){
	var r = [], l = this.length
	for (var i = 0; i < l; i++) r.pushc(f(this[i], i))
	return r
}
Array.prototype.random = function(){ return this[Math.floor(Math.random() * this.length)] }
// array.get(0) is like array[0] except doesn't go out of bounds
// Array.prototype.get = function(n){ return this.splice(n,n+1) }

//function visible(o){ return o.style.display != 'none' }
function toggle(o){ if (visible(o)) hide(o); else show(o) }
function invisible(o) { o.style.visibility = 'hidden' }
function hide(o){ o.style.display = 'none'; }
function show(o){ o.style.display = ''; o.style.visibility = '' }
function remove(){ for(var i=0, o; o=arguments[i]; i++) if(o && o.parentNode) o.parentNode.removeChild(o) }
function create(o,t){
	if (o == 'text') return document.createTextNode(t||'')
	else {
		var e = document.createElement(o)
		if (t) {
			if (typeof t == 'string') e.innerHTML = t
			else niceExtend(e, t)
		}
		return e
}}


// 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()})] }
}

function getTextStyle(o){
	return { fontSize: getStyle(o, 'font-size'), fontFamily: getStyle(o, 'font-family'), fontWeight: getStyle(o, 'font-weight') }
}
function makeTextSize(style, appendTo){
	style = extend({zborder: '1px solid red', visibility: 'hidden', position: 'absolute', top: 0, left: 0}, style)
	var div = create('div', {style: style})
	appendTo.appendChild(div)
	return div
}
function getTextSize(text, o){
	o.innerHTML = text.escHtml().replace(/ /g, '&nbsp;')
	return o.offsetWidth
}
function getTextWidth(text, style, appendTo){
	style = extend({border: '1px solid red', zvisibility: 'hidden', position: 'absolute', top: 0, left: 0}, style)
	var div = create('div', {style: style, html: text.escHtml().replace(/ /g, '&nbsp;')})
	appendTo.appendChild(div)
	var w = div.offsetWidth
	remove(div)
	return w
}

function $id(id){ if (typeof id == 'string') return document.getElementById(id); return id }