// if namespace YS is not defined, this defines it

if(!YS){
	var YS = new Object;
}
 

YS.IMAGESFILEREF = "/c/img";
YS.MENUFILEREFTOP = "/menu";
YS.MENUFILEREFFOOTER = "/footer";
YS.RATINGFILEREF = "/buttons/rating";
YS.MEDIAACTIONFILEREF = "/buttons/detailedMediaActions";
YS.MAXCOMMENTCHARCOUNT = 500;
YS.commentMessages = new Array();
YS.commentMessages['exceeded'] = "Number of characters over the limit: ";
YS.commentMessages['remaining'] = "Remaining character count: ";


YS.regexpvalueOff = /^.*[/](.*)_off.gif$/;
YS.regexpvalueOn = /^.*[/](.*)_on.gif$/;

YS.openPopupWindow = function(page){
	window.open(page,"Jukebox",'toolbar=0,location=0,directories=0,status=0,menubar=0,scrollbars=0,resizable=0,copyhistory=0,width=432,height=640');
}

YS.gel = function(elementid){
	return document.getElementById(elementid);
}

YS.switchMenuOnLocation = function(location){
	if(location == 'top'){
		return YS.MENUFILEREFTOP;
	} else if(location == 'footer'){
		return YS.MENUFILEREFFOOTER;
	}
}

YS.toggleMenuItemOn = function(element, location){
	YS.toggle(element, YS.switchMenuOnLocation(location), "on");	
}
YS.toggleMenuItemOff = function(element, location){
	YS.toggle(element, YS.switchMenuOnLocation(location), "off");
}
YS.toggleRatingItemOn = function(element){
	YS.toggle(element, YS.RATINGFILEREF, "on");	
}
YS.toggleRatingItemOff = function(element){
	YS.toggle(element, YS.RATINGFILEREF, "off");
}
YS.toggleMediaActionItemOn = function(element){
	YS.toggle(element, YS.MEDIAACTIONFILEREF, "on");	
}
YS.toggleMediaActionItemOff = function(element){
	YS.toggle(element, YS.MEDIAACTIONFILEREF, "off");
}


// used to save state for the parts of media upload ajax view that is not stored
// on server
// TODO:refactor all this
YS.fileUpload = new Object();
YS.fileUpload.isComplete = false;

YS.fileUpload.setCompleteStep1 = function(elementid){
	YS.toggleVisibility(elementid, 'block');
	YS.fileUpload.isComplete = true;
}

YS.fileUpload.hideUploadFileStep1 = function(elementid){
	YS.toggleVisibility(elementid, 'none')
}

YS.fileUpload.showUploadedFilename = function(elementid){
	YS.toggleVisibility(elementid, 'block');
}

YS.toggleVisibility = function(elementid, visibility){
	var element = YS.gel(elementid);
	if(element){
		element.style.display = visibility;
	}
}

YS.formElementState = new Object();
YS.formElementState.enabledStateArray = new Array();

YS.formElementState.getElementIdOrName = function(element){
	if(YS.gel(element)){
		return element.id;
	} else {
		return element.name;
	}
}

YS.formElementState.existsInArray = function(array, searchstring){
	array.sort();
	var found = false;
	for(var i = 0; i < array.length; i++) {
		if(array[i] == searchstring){
			found = true;
			break;
		}
	}
	return found;
}

YS.formElementState.disableFormInputs = function(){
	var nForms = document.forms.length;
	for(var i = 0; i < nForms; i++){
		var nElements = document.forms[i].elements.length;
		for(var j = 0; j < nElements; j++){
			var element = document.forms[i].elements[j];
			// alert("element.id=" + element.id + "; element.name=" +
			// element.name + "; element.disabled=" + element.disabled);
			if(element.disabled == true){
				var elementidorname = YS.formElementState.getElementIdOrName(element)
				YS.formElementState.enabledStateArray.push(elementidorname);
			} else {
				element.disabled = true;
			}
		}
	}
}
// make sure we remember which elements were disabled so we don't keep them
// enabled after this process
YS.formElementState.enableFormInputs = function(){
	// ease the search in the array further down
	YS.formElementState.enabledStateArray.sort();
	var nForms = document.forms.length;
	for(var i = 0; i < nForms; i++){
		var nElements = document.forms[i].elements.length;
		for(var j = 0; j < nElements; j++){
			var element = document.forms[i].elements[j];
			if(YS.formElementState.existsInArray(YS.formElementState.enabledStateArray, YS.formElementState.getElementIdOrName(element))){
				element.disabled = true;
			} else {
				element.disabled = false;
			}
		}
	}
	// empty array (delete it)
	enabledStatYS.formElementState.enabledStateArray.length = 0;
}

YS.getRegexp = function(state){
	if(state == "on"){
		return YS.regexpvalueOff;
	} else {
		return YS.regexpvalueOn;
	}
}

YS.toggle = function(element, typeRef, state){
	// alert("--toggle: element=" + element + "; typeRef=" + typeRef + ";
	// state=" + state);
	// alert("element.nodeName=" + element.nodeName);
	var imagesarray = new Array();
	if(element.nodeName == 'A' || element.nodeName == 'a'){ // if the toggled
															// element is an
															// anchor (eg menu
															// items)
		// alert("a");
		imagesarray = element.getElementsByTagName('img');
	} else if(element.nodeName == 'INPUT' || element.nodeName == 'input'){ // if
																			// the
																			// toggled
																			// element
																			// is a
																			// button
																			// with
																			// an
																			// image
																			// (eg
																			// rating
																			// buttons)
		// alert("input");
		imagesarray[0] = element;
	}
	for(var i = 0; i < imagesarray.length; i++) {
		// alert("getRegexp(" + state + ")=" + getRegexp(state));
		matcher = YS.getRegexp(state).exec(imagesarray[i].src);
		imagesarray[i].src = YS.APPLICATIONBASEURL + YS.IMAGESFILEREF + typeRef + "/" + matcher[1] + "_" + state + ".gif";
	}
}


YS.findFCKInstanceName = function(spanIdentifier) {
	// we find the span element that identifies the editor.
	// so each editor can be addressed on a stage with multiple editors
	// alert(">findFCKInstanceName spanIdentifier=" + spanIdentifier);
	var iframeInstanceNamePattern = /.*InstanceName\=([a-zA-Z0-9%:_]*).*/;
	var childIdElement = YS.gel(spanIdentifier);
	var editorIFrameElement = childIdElement.firstChild.nextSibling;
	var regExp = new RegExp(iframeInstanceNamePattern);
	var srcString = editorIFrameElement.src;
	var match = regExp.exec(srcString);
	if (match != null) {
		editorInstanceName = match[1];
	} else {
		// alert("FCKeditor instance name parsing error. Check FCKeditor DOM
		// structure for the cause.");
	}
	return editorInstanceName;
}

YS.extractMetadata = function(string) {
	// alert(">YS.extractMetadata string=" + string);
	var parameterArray = string.split(/_/);
	var metadataObject = new Array();
	for (var j = 0; j < parameterArray.length; j++) {
		var mapArray = parameterArray[j].split(/-/);
		// remove first value of key which is the '__ysembed ' string
		var tempkey = mapArray[0];
		var key = tempkey.replace(/__ysembed /, ""); 
		var value = mapArray[1];
		// alert("key=" + key + "; value=" + value);
		// An ugly, static way of attaching new properties to the object.
		// Would be nice to add them dynamically disregarding name of property
		switch (key) {
		case 'type':
			metadataObject.type = value;
			break;
		case 'mediaId':
			value = parseInt(value);
			metadataObject.mediaId = value;
			break;
		case 'cellVersionSparkId':
			value = parseInt(value);
			metadataObject.cellVersionSparkId = value;
			break;
		case 'mediaSnapMediumId':
			value = parseInt(value);
			metadataObject.mediaSnapMediumId = value;
			break;
		case 'mediaSnapCellId':
			value = parseInt(value);
			metadataObject.mediaSnapCellId = value;
			break;
		case 'mediaType':
			metadataObject.mediaType = value;
			break;
		}
	}
	return metadataObject;
}

YS.findElementsByClassName = function(oElm, strTagName, strClassName) {
	// alert(">YS.findElementsByClassName");
	var arrElements = (strTagName == "*" && oElm.all) ? oElm.all : oElm
			.getElementsByTagName(strTagName);
	var arrReturnElements = new Array();
	strClassName = strClassName.replace(/\-/g, "\\-");
	var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
	var oElement;
	for (var i = 0; i < arrElements.length; i++) {
		oElement = arrElements[i];
		if (oRegExp.test(oElement.className)) {
			arrReturnElements.push(oElement);
		}
	}
	// alert("<YS.findElementsByClassName");
	return arrReturnElements;
}

YS.removeEmptyYSEmbeds = function(content) {
	// this div will not be attached to document. We use it for the traversing
	// of the content string.
	var root = document.createElement("div");
	root.innerHTML = content;
	var spanElements = YS.findElementsByClassName(root, "span", "__ysembed");
	// alert(spanElements.length + " spans found");
	for (var i = 0; i < spanElements.length; i++) {
		var element = spanElements[i];
		var parent = element.parentNode;
		// check if element contains anchor and img element. if, remove it
		if (element.firstChild.nodeName == 'a' || element.firstChild.nodeName == 'A') {
			// found span with anchor. keep it.
			// alert("found span with anchor. keep.");
		} else if (element.firstChild.nodeName == 'img' || element.firstChild.nodeName == 'IMG') {
			// found span with image. keep it.
			// alert("found span with image. keep.");
		} else if (element.firstChild) {
			// found span with other content. remove it.
			// alert("found span with other content. remove.");
			parent.removeChild(element);
		}
	}
	return root.innerHTML;
}

YS.transformMetadataSpanElements = function(hiddenContentElement, cellid) {
	// alert(">YS.transformMetadataSpanElements hiddenContentElement=" +
	// hiddenContentElement);
	var actualContentElement = YS.gel(hiddenContentElement).firstChild;
	// find elements with class __ysembed
	var ysembedspans = YS.findElementsByClassName(actualContentElement, 'span',
			'__ysembed');
	// alert("ysembedspans.length=" + ysembedspans.length);
	// traverse the content and find span elements with class __ysembed.
	for (var i = 0; i < ysembedspans.length; i++) {
		// find value of the id attribute to extract the metadata
		var paramobj = YS.extractMetadata(ysembedspans[i].getAttribute("class"));

		// replace metadata span element with appropriate element
		switch (paramobj.type) {
		case 'thumblink':
			var newimg = document.createElement('img');
			var newanchor = document.createElement('a');
			newanchor.href = APPLICATIONBASEURL + "/" + paramobj.mediaType
					+ "/" + paramobj.mediaId;
			newimg.src = APPLICATIONBASEURL + "/" + paramobj.mediaSnapMediumId;
			newanchor.appendChild(newimg);
			var parentE = ysembedspans[i].parentNode;
			parentE.replaceChild(newanchor, ysembedspans[i]);
			break;
		case 'videoembed':
			var embedSpan = document.createElement('span');
			embedSpan.id = "visibleembedspan" + cellid;
			var fo = new SWFObject(APPLICATIONBASEURL
					+ "/flash/flowplayer/FlowPlayerDark.swf", "FlowPlayer",
					"366", "275", "7", "#ffffff", true);
			// need this next line for local testing, it's optional if your swf
			// is on the same domain as your html page
			fo.addParam("allowScriptAccess", "always");
			fo
					.addVariable(
							"config",
							"{ loop:false, showStopButton: true, autoPlay: false, autoBuffering: false, initialScale: 'scale', countryCode: 'se', playList: [ { url: '"
									+ APPLICATIONBASEURL
									+ "/media/"
									+ paramobj.mediaSnapCellId
									+ ".jpg', overlayId: 'play' }, { url: '"
									+ APPLICATIONBASEURL
									+ "/media/"
									+ paramobj.cellVersionSparkId
									+ ".flv' } ], fullScreenScriptURL: '"
									+ APPLICATIONBASEURL
									+ "/flash/flowplayer/fullscreen.js' }");
			embedSpan.innerHTML = fo.getSWFHTML();
			var parentE = ysembedspans[i].parentNode;
			parentE.replaceChild(embedSpan, ysembedspans[i]);
			break;
		case 'soundembed':
			var embedSpan = document.createElement('span');
			embedSpan.id = "visibleembedspan" + cellid;

			var embedText = "<object width='366' height='275'>";
			embedText += "<param name='config' value={loop:false, showStopButton: true, autoPlay: false, autoBuffering: false, initialScale: 'scale', countryCode: 'se', playList: [ { url: '";
			embedText += APPLICATIONBASEURL;
			embedText += "/media/";
			embedText += paramobj.mediaSnapCellId;

			embedText += ".jpg', overlayId: 'play' }, { url: '";
			embedText += APPLICATIONBASEURL;
			embedText += "/media/";
			embedText += paramobj.cellVersionSparkId;
			embedText += ".flv' } ], fullScreenScriptURL: '";
			embedText += APPLICATIONBASEURL;
			embedText += "/flash/flowplayer/fullscreen.js'}>";
			embedText += "<embed width='366' heigth='275' ";
			embedText += "flashvars='config={loop:false, showStopButton: true, autoPlay: false, autoBuffering: false, initialScale: 'scale', countryCode: 'se', playList: [ { url: '";

			embedText += APPLICATIONBASEURL;
			embedText += "/media/";
			embedText += paramobj.mediaSnapCellId;
			embedText += ".jpg', overlayId: 'play' }, { url: '";
			embedText += APPLICATIONBASEURL;
			embedText += "/media/";
			embedText += paramobj.cellVersionSparkId;
			embedText += ".flv' } ], fullScreenScriptURL: '";

			embedText += APPLICATIONBASEURL;
			embedText += "/flash/flowplayer/fullscreen.js'}'";
			embedText += "quality='high' ";
			embedText += "bgcolor='#ffffff' ";
			embedText += "name='FlowPlayer' ";
			embedText += "id='FlowPlayer' ";
			embedText += "src='";
			embedText += APPLICATIONBASEURL;
			embedText += "/flash/flowplayer/FlowPlayerDark.swf' ";
			embedText += "type='application/x-shockwave-flash'";
			embedText += "/>";
			embedText += "</object>";

			embedSpan.innerHTML = embedText;
			var parentE = ysembedspans[i].parentNode;
			parentE.replaceChild(embedSpan, ysembedspans[i]);
			break;
		}
	}
	var resultingContent = actualContentElement.innerHTML;
	return resultingContent;
}

YS.logout = function() {
	Seam.Component.getInstance("userServiceRemote").logout(
			logoutResponseCallback);
	return false;
}

logoutResponseCallback = function(result) {
	// delete autologin cookies for jforum
	YS.deleteCookie('JforumSSOUsername', '.snowfish.com');
	YS.deleteCookie('JforumSSOAuthkey', '.snowfish.com');
	var pos = window.location.href.indexOf('#');
	if (pos == -1) {
		alert(window.location.href);
	} else {
		window.location.href = window.location.href.substring(0,pos);
	}
}

YS.setStyleProperty = function(elementId, property, value){
	YS.gel(elementId).style.property = value;
}

YS.setStyleProperties = function(elementId, properyArray, valueArray){
	// not yet implemented
}

YS.updateCharCount = function(charcount, charcountlabel, commentinput){
	if(commentinput.value.length > YS.MAXCOMMENTCHARCOUNT) {
		// alert("showing " + YS.commentMessages["exceeded"]);
		// alert("length over max");
		if(YS.gel(charcountlabel).innerHTML != YS.commentMessages["exceeded"]) {
			// alert("exceededtext on");
			YS.gel(charcountlabel).innerHTML = YS.commentMessages["exceeded"];
		}
		YS.gel(charcount).firstChild.value = (commentinput.value.length-YS.MAXCOMMENTCHARCOUNT);
	} else {
		// alert("showing " + YS.commentMessages["remaining"]);
		// alert("length under max");
		if(YS.gel(charcountlabel).innerHTML != YS.commentMessages["remaining"]) {
			// alert("remaintext on");
			YS.gel(charcountlabel).innerHTML = YS.commentMessages["remaining"];
		}
		// alert("max=" + YS.MAXCOMMENTCHARCOUNT);
		// alert("length=" + commentinput.value.length);
		// alert("setting value to " +
		// (YS.MAXCOMMENTCHARCOUNT-commentinput.value.length));
		YS.gel(charcount).firstChild.value = (YS.MAXCOMMENTCHARCOUNT-commentinput.value.length);
	}
		
}

YS.changeParamAndRedirect = function(key, value) {
	var parameters, cx;
	parameters = location.search.split(/[&?]/);
	for (cx = 0; cx < parameters.length; cx++)
	{
		parameters[cx] = parameters[cx].split("=");
		if (parameters[cx].length < 2) // Drop "" or /[A-Za-z]\w*=$/
			parameters.splice(cx--, 1);
	}

	var newSearch='';
	var found=false;
	while (parameters.length)
	{
		parameter = parameters.shift();
		newSearch += parameter[0];
		newSearch += '=';
		if (parameter[0] == key) {
			newSearch+=value;
			found=true;
		}
		else
			newSearch+=parameter[1];
		if (parameters.length)
			newSearch+='&';
	}

	if (!found)
	{
		newSearch+='&';
		newSearch+=key;
		newSearch+='=';
		newSearch+=value;
	}
	window.location.href = window.location.protocol + '//' +  window.location.host + window.location.pathname +'?' +newSearch + window.location.hash ;
}

YS.copyFormField = function(checkbox, src, destination){
	if(checkbox.checked){
		var srcElement = YS.gel(src);
		var destinationElement = YS.gel(destination);
		destinationElement.value = srcElement.value;
	}
}

YS.deleteCookie = function (cookie_name, domain){
	var cookie_date = new Date ( );
	cookie_date.setTime ( cookie_date.getTime() - 1 );
	document.cookie = cookie_name += "=; expires=" + cookie_date.toGMTString() + "; domain=" + domain;
}

YS.mouseX = function(evt) {
	if (evt.pageX) {
		return evt.pageX;
	}
	else if (evt.clientX) {
		return evt.clientX + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft);
	} else {
		return null;
	}
}
YS.mouseY = function(evt) {
	if (evt.pageY) {
		return evt.pageY;
	}
	else if (evt.clientY) {
		return evt.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);
	} else {
		return null;
	}
}

YS.postCommentReplyCallback = function(result, commentId) {
	YS.gel('divComment' + commentId).style.display = 'none';
	YS.gel('divThanks' + commentId).style.display = 'block';
	YS.gel('divReplyToLong' + commentId).style.display = 'none';
	YS.gel('textAreaComment' + commentId).value = ''; 
}

YS.postCommentCallback = function(result) {
	YS.gel('divThanks').style.display = 'block';
	YS.gel('textAreaComment').value = '';
	YS.gel('divReplyToLong').style.display = 'none';
	document.forms['blogcommentform'].elements['textAreaComment'].disabled = true;
	document.forms['blogcommentform'].elements['commentButton'].disabled = true;
}

YS.postCommentExceptionHandler = function(ex) {
	YS.gel('divReplyToLong').style.display = 'block';
}

YS.postCommentReplyExceptionHandler = function(ex, commentId) {
	YS.gel('divReplyToLong' + commentId).style.display = 'block';
}

YS.deleteCommentCallback = function(result, commentId) {
	// replace avatar with "nocomment image"
	var avatarElement = YS.gel('avatar' + commentId);
	avatarElement.src = YS.APPLICATIONBASEURL + '/c/img/mediaStatus/FAILED/IMAGE/small.gif';
	// replace comment text with "comment deleted"
	var commentBodyElement = YS.gel('commentDiv' + commentId);
	commentBodyElement.innerHTML = '';
	var commentHeaderLeftElement = YS.gel('commentHeaderLeft' + commentId);
	commentHeaderLeftElement.innerHTML = 'This comment has been deleted.';
	var commentHeaderRightElement = YS.gel('commentHeaderRight' + commentId);
	commentHeaderRightElement.innerHTML = '';
}

YS.deleteCommentExceptionHandler = function(ex, commentId) {
	
}

YS.postBlogCommentReply = function(blogCellId, rootId, parentId, visualParentId, message) {
	Seam.Component.getInstance("commentingRemote").postBlogCommentReply(blogCellId, rootId, parentId, message, 
		function(result) {
			YS.postCommentReplyCallback(result, visualParentId);
		}, 
		function(ex) {
			YS.postCommentReplyExceptionHandler(ex, visualParentId);
		}
	);
	return false;
} 

YS.postMediaCommentReply = function(mediaId, parentId, visualParentId, message, conversationId) {
	Seam.Remoting.getContext().setConversationId(conversationId);
	Seam.Component.getInstance("commentingRemote").postMediaCommentReply(mediaId, parentId, message, 
		function(result) {
			YS.postCommentReplyCallback(result, visualParentId);
		}, 
		function(ex) {
			YS.postCommentReplyExceptionHandler(ex, visualParentId);
		}
	);
	return false;
}

YS.postBlogComment = function(blogCellId, rootId, message) {
	Seam.Component.getInstance("commentingRemote").postBlogComment(blogCellId, rootId, message, 
		function(result) {
			YS.postCommentCallback(result);
		}, 
		function(ex) {
			YS.postCommentExceptionHandler(ex);
		}
	);
	return false;
}

YS.postMediaComment = function(mediaId, message, conversationId) {
	Seam.Remoting.getContext().setConversationId(conversationId);
	Seam.Component.getInstance("commentingRemote").postMediaComment(mediaId, message,
		function(result) {
			YS.postCommentCallback(result);
		},
		function(result) {
			YS.postCommentExceptionHandler(ex);
		}
	);
	return false;
}

YS.deleteMediaComment = function(mediaId, messageId, conversationId) {
	Seam.Remoting.getContext().setConversationId(conversationId);
	Seam.Component.getInstance("commentingRemote").deleteMediaComment(mediaId, messageId,
		function(result) {
			YS.deleteCommentCallback(result, messageId);
		},
		function(result) {
			YS.deleteCommentExceptionHandler(ex, messageId);
		}
	);
	return false;
}

YS.deleteBlogComment = function(blogCellId, rootObjectId, messageId, conversationId) {
	Seam.Remoting.getContext().setConversationId(conversationId);
	Seam.Component.getInstance("commentingRemote").deleteBlogComment(blogCellId, rootObjectId, messageId,
		function(result) {
			YS.deleteCommentCallback(result, messageId);
		},
		function(result) {
			YS.deleteCommentExceptionHandler(ex, messageId);
		}
	);
	return false;
}


YS.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 var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
}


YS.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;
}

YS.eraseCookie = function(name) {
	YS.createCookie(name,"",-1);
}

YS.cookieCheck = function() {
	var jsessionid=YS.readCookie("JSESSIONID");
	if (jsessionid != null && jsessionid.indexOf(".") != -1)
	{
		YS.deleteCookie("JSESSIONID");
		alert("dfdf");
		window.location.href="http://snowfish.com";		
	}
}

function twitterCallback2(twitters) {
	  var statusHTML = [];
	  for (var i=0; i<twitters.length; i++){
	    var username = twitters[i].user.screen_name;
	    var status = twitters[i].text.replace(/((https?|s?ftp|ssh)\:\/\/[^"\s\<\>]*[^.,;'">\:\s\<\>\)\]\!])/g, function(url) {
	      return '<a href="'+url+'">'+url+'</a>';
	    }).replace(/\B@([_a-z0-9]+)/ig, function(reply) {
	      return  reply.charAt(0)+'<a href="http://twitter.com/'+reply.substring(1)+'">'+reply.substring(1)+'</a>';
	    });
	    statusHTML.push('<li><span>'+status+'</span> <a style="font-size:85%" href="http://twitter.com/'+username+'/statuses/'+twitters[i].id+'">'+relative_time(twitters[i].created_at)+'</a></li>');
	  }
	  document.getElementById('twitter_update_list').innerHTML = statusHTML.join('');
	}

function relative_time(time_value) {
	  var values = time_value.split(" ");
	  time_value = values[1] + " " + values[2] + ", " + values[5] + " " + values[3];
	  var parsed_date = Date.parse(time_value);
	  var relative_to = (arguments.length > 1) ? arguments[1] : new Date();
	  var delta = parseInt((relative_to.getTime() - parsed_date) / 1000);
	  delta = delta + (relative_to.getTimezoneOffset() * 60);

	  if (delta < 60) {
	    return 'less than a minute ago';
	  } else if(delta < 120) {
	    return 'about a minute ago';
	  } else if(delta < (60*60)) {
	    return (parseInt(delta / 60)).toString() + ' minutes ago';
	  } else if(delta < (120*60)) {
	    return 'about an hour ago';
	  } else if(delta < (24*60*60)) {
	    return 'about ' + (parseInt(delta / 3600)).toString() + ' hours ago';
	  } else if(delta < (48*60*60)) {
	    return '1 day ago';
	  } else {
	    return (parseInt(delta / 86400)).toString() + ' days ago';
	  }
}
