window.addEvent('domready',function(){
	if($('extraSmallImage'))
	{
		resizeExtraSmallImageIfNecessary();
	}
	if($('readFullArticle'))
	{
		removeReadFullArticleLinkIfArticleIsTooShort($('readFullArticle'));
	}
});
function toggleArticle(button)
{
	button.innerHTML = (button.innerHTML=='read full article') ? 'collapse article' : 'read full article';
	button.className = (button.className == 'readFullArticle') ? 'collapseArticle' : 'readFullArticle';
	var innerContainerHeight = (($('innerArticleBody').offsetHeight*1)+20);
	$('articleBody').tween('height',($('articleBody').clientHeight==300)?innerContainerHeight:300);
}
function removeReadFullArticleLinkIfArticleIsTooShort(button)
{
	var innerContainerHeight = (($('innerArticleBody').offsetHeight*1)+20);
	if(innerContainerHeight < 300)
	{
		$('articleBody').style.height = innerContainerHeight;
		button.parentNode.removeChild(button);
	}
}
function openPrintArticleWindow()
{
	var printText = '';
	printText += ($('banner_url')) ? $('banner_url').innerHTML : '';
	printText += ($('logo_url')) ? $('logo_url').innerHTML : '';
	printText += ($('innerArticleBody')) ? '<div style="font-family:Arial,Helvetica,sans-serif; font-size:11px;">'+$('innerArticleBody').innerHTML+'</div>' : '';
	
	var myWindow = window.open('','Print','width=500,height=500,scrollbars=yes');
	myWindow.document.open();
	myWindow.document.write(printText);
	myWindow.document.close();
	if(Browser.Engine.name=='presto')
	{
		myWindow.onload = myWindow.print;
	}
	else
	{
		myWindow.print();
	} 
}
var limit = 30; 
var startingLimit = 0;
function setLimitsAndFilterProductsTop(slim,lim)
{
	location.href='#products';
	limit = lim;
	startingLimit = slim;
	filterProducts();
}
function setLimitsAndFilterProductsBottom(slim,lim)
{
	location.href='#products';
	limit = lim;
	startingLimit = slim;
	filterProducts();
}
function filterProducts()
{
	var filters = $$('.filterDropDowns');
	var params='&limit='+limit+'&startingLimit='+startingLimit;
	if(filters)
	{
		for(var i = 0; i < filters.length; i++)
		{
			var split = filters[i].value.split('|');
			var filterType = split[0];
			var value = split[1];
			params+='&'+filterType+'_ids['+i+']='+value;
		}
	}
	$('productDisplayArea').innerHTML='<h3>Searching for matching products...</h3>';
	new Request({
		method:'post',
		url:'/p_include/ajax_func.html',
		onComplete:function(response)
		{
			$('productDisplayArea').innerHTML=response;
		}
	}).send('func=filterModuleTemplateProducts'+params+'&module_template_id='+$('module_template_id').value);
	//do the request even with no filters (could be using limits only)
}
function toggleModuleTabs(divId)
{
	var contentAreas = $$('.moduleTabsContent');
	var tabs = $$('.moduleTabs');
	for (var i = 0; i < contentAreas.length; i++)
	{
		contentAreas[i].style.display = 'none';
	}
	$(divId).style.display='';
	for(var i = 0; i < tabs.length; i++)
	{
		tabs[i].removeClass('active');
	}
	$(divId+'Tab').addClass('active');
}
function postAComment(divId)
{
//	toggleModuleTabs(divId);
	if($('postAComment').getStyles('display').display == 'none')
	{
		$('postAComment').style.display='';
	}
	else
	{
		$('postAComment').style.display='none';
	}
//	if($('postAComment').offsetHeight == 0)
//	{
//		$('postAComment').tween('height','205px');
//	}
//	else $('postAComment').tween('height','0px');
}
function postAReply(post_node_id)
{
	if($('newComment'+post_node_id).getStyles('display').display == 'none')
	{
		$('newComment'+post_node_id).style.display='';
	}
	else
	{
		$('newComment'+post_node_id).style.display='none';
	}
		
//	if($('newComment'+post_node_id).offsetHeight == 0)
//	{
//		
//		$('newComment'+post_node_id).set('tween',{
//			onComplete:function()
//			{
//				$('newComment'+post_node_id).style.overflow='';		
//			}
//		}).tween('height',height);
//	}
//	else 
//	{
//		$('newComment'+post_node_id).set('tween',{
//			onComplete:function()
//			{
//				$('newComment'+post_node_id).style.overflow='hidden';		
//			}
//		}).tween('height','0');
//	}
}
function replyToNode(post_node_id,thread_depth,product_id,bundle_id,template_usage_id,master_node_id)
{
	$('ThreadNodeReply_'+post_node_id).setStyle('display','block');
	$('ThreadNodeReply_'+post_node_id).innerHTML = 'Loading...';
	new Request({
		method:'post',
		url:'/p_include/ajax_func.html',
		onComplete:function()
		{
			$('ThreadNodeReply_'+post_node_id).innerHTML = this.response.text;
		}
	}).send('func=returnPostANewNodeForm&post_node_id='+post_node_id+'&thread_depth='+thread_depth+'&product_id='+product_id+'&bundle_id='+bundle_id+'&template_usage_id='+template_usage_id+'&master_node_id='+master_node_id);
}
function newReview()
{
	if($('newReview').getStyles('display').display == 'none')
		$('newReview').style.display='';
	else $('newReview').style.display='none';
}
function starHover(star)
{
	for (var i = 1; i <= 5; i++)
	{
		if(i <= star)
		{
			$(i+'star').removeClass('emptyStar');
			$(i+'star').addClass('potentialStar');
		}
		else
		{
			$(i+'star').removeClass('potentialStar');
			if($(i+'star').className.search('wholeStar') != -1)
				$(i+'star').addClass('wholeStar');
			else
				$(i+'star').addClass('emptyStar');			
		}
	}
}
function removeStarHover()
{
	for (var i = 1; i <= 5; i++)
	{
		$(i+'star').removeClass('potentialStar');
		if($(i+'star').className.search('wholeStar') != -1)
			$(i+'star').addClass('wholeStar');
		else
			$(i+'star').addClass('emptyStar');			
	}
}
function selectRating(star,is_bottom)
{
	
	if(is_bottom == 1)
	{
		$('rating_bot').value=star;
		for (var i = 1; i <= 5; i++)
		{
			if(i <= star)
			{
				$(i+'star_bot').removeClass('potentialStar');
				$(i+'star_bot').removeClass('emptyStar');
				$(i+'star_bot').addClass('wholeStar');
			}
			else
			{
				$(i+'star_bot').removeClass('potentialStar');
				$(i+'star_bot').removeClass('wholeStar');
				$(i+'star_bot').addClass('emptyStar');
			}
		}
	}
	else
	{
		$('rating').value=star;
		for (var i = 1; i <= 5; i++)
		{
			if(i <= star)
			{
				$(i+'star').removeClass('potentialStar');
				$(i+'star').removeClass('emptyStar');
				$(i+'star').addClass('wholeStar');
			}
			else
			{
				$(i+'star').removeClass('potentialStar');
				$(i+'star').removeClass('wholeStar');
				$(i+'star').addClass('emptyStar');
			}
		}
	}
}

function togglePostNodeChildren(post_node_id,yesJustOpen)
{
	if(yesJustOpen==1){
		$('ThreadChildrenTitle_'+post_node_id).innerHTML = 'Hide Replies';
		$('ThreadChildren_'+post_node_id).setStyle('display','block');
		$('ThreadChildren_'+post_node_id).removeClass('HideChildren');
		$('ThreadChildren_'+post_node_id).addClass('ViewChildren');
	}
	else if($('ThreadChildren_'+post_node_id).hasClass('HideChildren')){
		$('ThreadChildrenTitle_'+post_node_id).innerHTML = 'Hide Replies';
		$('ThreadChildren_'+post_node_id).setStyle('display','block');
		$('ThreadChildren_'+post_node_id).removeClass('HideChildren');
		$('ThreadChildren_'+post_node_id).addClass('ViewChildren');
	}
	else if($('ThreadChildren_'+post_node_id).hasClass('ViewChildren')){
		$('ThreadChildrenTitle_'+post_node_id).innerHTML = 'View Replies';
		$('ThreadChildren_'+post_node_id).setStyle('display','none');
		$('ThreadChildren_'+post_node_id).removeClass('ViewChildren');
		$('ThreadChildren_'+post_node_id).addClass('HideChildren');
	}
}

function viewComments(post_node_id)
{
	if($('viewComments'+post_node_id).innerHTML.search('View') != -1)
	{
		$('viewComments'+post_node_id).innerHTML = $('viewComments'+post_node_id).innerHTML.replace('View','Hide');
	}
	else
	{
		$('viewComments'+post_node_id).innerHTML = $('viewComments'+post_node_id).innerHTML.replace('Hide','View');
	}
	if($('comments'+post_node_id).getStyles('display').display == 'none')
	{
		$('comments'+post_node_id).style.display='';
	}
	else $('comments'+post_node_id).style.display='none';
//	if($('comments'+post_node_id).offsetHeight == 0)
//	{
//		$('comments'+post_node_id).set('tween',{
//			duration:1,
//			onComplete:function()
//			{
//				$('comments'+post_node_id).set('tween',{
//					onComplete:function()
//					{
//						$('comments'+post_node_id).style.height='auto';
//						$('comments'+post_node_id).style.overflow='';
//					}
//				}).tween('height',$('comments'+post_node_id).scrollHeight);
//			}
//		}).tween('height','5');
//	}
//	else 
//	{
//		$('comments'+post_node_id).tween('height','0');
//		$('comments'+post_node_id).style.overflow='hidden';
//	}
}
function submitReview(product_id,bundle_id,template_usage_id,formEl)
{
/*	var rating = url_encode($('rating').value);
	var username = url_encode($('username').value);
	var email = url_encode($('email').value);
	var title = url_encode(title);
	var body = url_encode(body);*/

/*	if(!rating) {alert('Please click on a star rating'); return;}
	if(!body) {alert('Please type a review in the review field'); return;}*/
	//loadingAnimation('postReviewButton' + ((product_id)?product_id:'') + ((bundle_id)?bundle_id:'') + ((template_usage_id)?template_usage_id:''));
	new Request({
		method:'post',
		url:'/p_include/ajax_func.html',
		onComplete:function(response)
		{
			response = JSON.decode(response);
			if(response.success == 1)
			{
				new Request({
					method:'post',
					url:'/p_include/ajax_func.html',
					onComplete:function(response)
					{
						try{
							if($('reviewContainer')){
								$('reviewContainer').innerHTML=response;
							}
						}
						catch(err){}
						
						try{
							if($('commentsSection')){
								$('commentsSection').innerHTML=response;
							}
						}
						catch(err){}
						
						var btn = '<p style="text-align:center;"><input type="button" value="Close" onclick="reloadProductReviews()" /></p>'
						showPopUp('<p style="text-align:center;" class="largerBlueHeader">Review Posted</p><p style="text-align:center;font-weight:bold;">Your review has been posted</p>'+btn,'','reloadProductReviews');
						try{togglePostNodeChildren(master_node_id,1)}catch(err){/*alert(err)*/}
					}
				}).send('func=refreshProductReviews&product_id='+product_id+'&bundle_id='+bundle_id+'&template_usage_id='+template_usage_id);
			}
			else
			{
				var string = 'Please correct the following errors before you submit your review.\n\n';
				for(var i = 0; i < response.error.length; i++)
				{
					string+=(i+1)+'. '+response.error[i]+'\n';
				}
				alert(string);
				//$(loadingId).innerHTML=contentPreviousToLoading;
			}
			stopLoadingAnimation();
		}
	}).send('func=submitReview'+returnXhrRequestFromFormStr(formEl)+'&product_id='+product_id+'&bundle_id='+bundle_id+'&template_usage_id='+template_usage_id);
	//}).send('func=submitReview&rating='+rating+'&username='+username+'&email='+email+'&title='+title+'&body='+body+'&product_id='+product_id+'&bundle_id='+bundle_id+'&template_usage_id='+template_usage_id);
}

function reloadProductReviews(){
	location.href='#productReviews';
	closePopUp();
}

function submitReplyToNode(product_id,bundle_id,template_usage_id,formEl,parent_node_id,thread_depth,master_node_id)
{
/*	var rating = url_encode($('rating').value);
	var username = url_encode($('username').value);
	var email = url_encode($('email').value);
	var title = url_encode(title);
	var body = url_encode(body);*/

/*	if(!rating) {alert('Please click on a star rating'); return;}
	if(!body) {alert('Please type a review in the review field'); return;}*/
	//loadingAnimation('postReviewButton' + ((product_id)?product_id:'') + ((bundle_id)?bundle_id:'') + ((template_usage_id)?template_usage_id:''));
	//alert("To be implemented!!!");
	
	new Request({
		method:'post',
		url:'/p_include/ajax_func.html',
		onComplete:function(response)
		{
			response = JSON.decode(response);
			if(response.success == 1)
			{
				var func = ($('reviewContainer')) ? 'refreshProductReviews' : 'refreshTemplateComments' ;
				new Request({
					method:'post',
					url:'/p_include/ajax_func.html',
					onComplete:function(response)
					{
						try{
							if($('reviewContainer')){
								$('reviewContainer').innerHTML=response;
							}
						}
						catch(err){alert(err)}
						
						try{
							if($('commentsSection')){
								$('commentsSection').innerHTML=response;
							}
						}
						catch(err){}
						
						var btn = '<p style="text-align:center;"><input type="button" value="Close" onclick="reloadProductReviews()" /></p>'
						showPopUp('<p style="text-align:center;" class="largerBlueHeader">Comment Posted</p><p style="text-align:center;font-weight:bold;">Your comment has been posted</p>'+btn,'','reloadProductReviews');
						try{togglePostNodeChildren(master_node_id,1)}catch(err){/*alert(err)*/}
					}
				}).send('func='+func+'&product_id='+product_id+'&bundle_id='+bundle_id+'&template_usage_id='+template_usage_id);
			}
			else
			{
				var string = 'Please correct the following errors before you submit your review.\n\n';
				for(var i = 0; i < response.error.length; i++)
				{
					string+=(i+1)+'. '+response.error[i]+'\n';
				}
				alert(string);
				//$(loadingId).innerHTML=contentPreviousToLoading;
			}
			stopLoadingAnimation();
		}
	}).send('func=submitComment'+returnXhrRequestFromFormStr(formEl)+'&type=reply&product_id='+product_id+'&bundle_id='+bundle_id+'&template_usage_id='+template_usage_id+'&parent_node_id='+parent_node_id+'&thread_depth='+thread_depth+'&master_none_id='+master_node_id);
	//}).send('func=submitReview&rating='+rating+'&username='+username+'&email='+email+'&title='+title+'&body='+body+'&product_id='+product_id+'&bundle_id='+bundle_id+'&template_usage_id='+template_usage_id);
}

function submitComment(post_node_id,product_id,bundle_id,template_usage_id,top_parent_node_type,thread_depth,master_node_id)
{
	var body = url_encode($('body'+post_node_id).value);
	var title = url_encode($('title'+post_node_id).value);
	var email = url_encode($('email'+post_node_id).value);
	var username = url_encode($('username'+post_node_id).value);
	
	if(!body) {alert('Please type a comment in the comment field'); return;}
	loadingAnimation('postCommentButton'+post_node_id);
	new Request({
		method:'post',
		url:'/p_include/ajax_func.html',
		onComplete:function(response)
		{
			response = JSON.decode(response);
			topMostParentNode = response.topMostParentNode;
			if(response.success == 1)
			{
				if(top_parent_node_type == 'comment')//posting a comment associated to a template page
				{
					new Request({
						method:'post',
						url:'/p_include/ajax_func.html',
						onComplete:function(response)
						{
							try{
								if($('reviewContainer')){
									$('reviewContainer').innerHTML=response;
								}
							}
							catch(err){}
							
							try{
								if($('commentsSection')){
									$('commentsSection').innerHTML=response;
								}
							}
							catch(err){}
							var btn = '<p style="text-align:center;"><input type="button" value="Close" onclick="reloadProductReviews()" /></p>'
							showPopUp('<p style="text-align:center;" class="largerBlueHeader">Comment Posted</p><p style="text-align:center;font-weight:bold;">Your comment has been posted</p>'+btn,'','reloadProductReviews');
							try{togglePostNodeChildren(master_node_id,1)}catch(err){/*alert(err)*/}
							if(topMostParentNode)
								viewComments(topMostParentNode);
							var numberOfComments = $('numberOfCommentsForRefresh').innerHTML;
							var commentsToRefresh = $$('.refreshNumberOfComments');
							for (var i = 0; i < commentsToRefresh.length; i++)
							{
								commentsToRefresh[i].innerHTML=numberOfComments;
							}
						}
					}).send('func=refreshTemplateComments&template_usage_id='+template_usage_id);
				}
				else if(top_parent_node_type == 'review') //posting a comment associate to a review page
				{
					new Request({
						method:'post',
						url:'/p_include/ajax_func.html',
						onComplete:function(response)
						{
							try{
								if($('reviewContainer')){
									$('reviewContainer').innerHTML=response;
								}
							}
							catch(err){}
							
							try{
								if($('commentsSection')){
									$('commentsSection').innerHTML=response;
								}
							}
							catch(err){}
							var btn = '<p style="text-align:center;"><input type="button" value="Close" onclick="reloadProductReviews()" /></p>'
							showPopUp('<p style="text-align:center;" class="largerBlueHeader">Comment Posted</p><p style="text-align:center;font-weight:bold;">Your comment has been posted</p>'+btn,'','reloadProductReviews');
							try{togglePostNodeChildren(master_node_id,1)}catch(err){/*alert(err)*/}
							if(topMostParentNode)
								viewComments(topMostParentNode);
							var numberOfReviews = $('reviewsToRefresh').innerHTML;
							var reviewsToRefresh = $$('.reviewsToRefresh');
							for (var i = 0; i < reviewsToRefresh.length; i++)
							{
								reviewsToRefresh[i].innerHTML=numberOfReviews;
							}
						}
					}).send('func=refreshProductReviews&product_id='+product_id+'&bundle_id='+bundle_id+'&template_usage_id='+template_usage_id);
				}
			}
			else
			{
				var string = 'Please correct the following errors before you submit your comment.\n\n';
				for(var i = 0; i < response.error.length; i++)
				{
					string+=(i+1)+'. '+response.error[i]+'\n';
				}
				alert(string);
				$(loadingId).innerHTML=contentPreviousToLoading;
			}
			stopLoadingAnimation();
		}
	}).send('func=submitComment&title='+title+'&body='+body+'&post_node_id='+post_node_id+'&template_usage_id='+template_usage_id+'&username='+username+'&email='+email);
}
function filterProductReviews(product_id,bundle_id,template_usage_id,rating,sortBy)
{
	new Request({
		method:'post',
		url:'/p_include/ajax_func.html',
		onComplete:function(response)
		{
						try{
							if($('reviewContainer')){
								$('reviewContainer').innerHTML=response;
							}
						}
						catch(err){}
						
						try{
							if($('commentsSection')){
								$('commentsSection').innerHTML=response;
							}
						}
						catch(err){}
		}
	}).send('func=refreshProductReviews&product_id='+product_id+'&bundle_id='+bundle_id+'&rating='+rating+'&sortBy='+sortBy+'&template_usage_id='+template_usage_id);
}
function rateThisPost(post_node_id,upDown)
{
	new Request({
		method:'post',
		url:'/p_include/ajax_func.html',
		onComplete:function(response)
		{
			$('rateThisPost'+post_node_id).innerHTML='Thank you for your feedback.';
		}
	}).send('func=rateThisPost&post_node_id='+post_node_id+'&upDown='+upDown);
}
function getOffset( el ) {
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
        _x += el.offsetLeft - el.scrollLeft;
        _y += el.offsetTop - el.scrollTop;
        el = el.parentNode;
    }
    return { top: _y, left: _x };
}

function reportToModerator(post_node_id,profile_id,el)
{
	//var scroll = getOffset(el);
	showPopUp('func=returnModerationWindow&post_node_id='+post_node_id+'&profile_id='+profile_id, '', '', '/p_include/ajax_func.html', '500');
}
function submitToModerator(type,post_node_id,profile_id)
{
	new Request({
		method:'post',
		url:'/p_include/ajax_func.html',
		onComplete:function(response){
			$('rateThisPost'+post_node_id).innerHTML=this.response.text;
			closePopUp();
		}
	}).send('func=reportToModerator&type='+type+'&post_node_id='+post_node_id+'&profile_id='+profile_id);
}
var loadingAnimationInterval;
var contentPreviousToLoading;
var loadingId;
function loadingAnimation(id)
{
	loadingId=id;
	contentPreviousToLoading=$(id).innerHTML;
	$(id).innerHTML='Loading.';
	loadingAnimationInterval = window.setInterval(function(){
		switch($(id).innerHTML)
		{
			case 'Loading.':
				$(id).innerHTML='Loading..';
				break;
			case 'Loading..':
				$(id).innerHTML='Loading...';
				break;
			case 'Loading...':
				$(id).innerHTML='Loading.';
				break;
		}
	},200);
}
function stopLoadingAnimation()
{
	loadingAnimationInterval = window.clearInterval(loadingAnimationInterval);
}
function editPost(id)
{
	if(!isNaN(id))
	{
		$('post_title_'+id).innerHTML = '<textarea id="post_title_edit_'+id+'" style="width:300px;height:20px;">'+$('post_title_'+id).innerHTML+'</textarea>';
		$('post_body_'+id).innerHTML = '<textarea id="post_body_edit_'+id+'" style="width:516px;height:20px;">'+$('post_body_'+id).innerHTML+'</textarea><input type="button" onclick = "saveEditedPost('+id+')" value = "Save"/>';
	}
}
function saveEditedPost(id)
{
	if(!isNaN(id))
	{
		new Request({
			method:'post',
			url:'/p_include/ajax_func.html',
			onComplete:function(response){
				$('post_title_'+id).innerHTML = $('post_title_edit_'+id).value;
				$('post_body_'+id).innerHTML = $('post_body_edit_'+id).value;
			}
		}).send('func=saveEditedPost&post_node_id='+id+'&title='+url_encode($('post_title_edit_'+id).value)+'&body='+url_encode($('post_body_edit_'+id).value));
	}	
}
function resizeExtraSmallImageIfNecessary()
{
	if($('extraSmallImage').width > 60)$('extraSmallImage').style.width=60;
}
function hideReviews(button)
{
	if(button.innerHTML.search('Hide') != -1)
	{
		button.innerHTML = button.innerHTML.replace('Hide','View');
		$('reviewsContainer').style.display='none';
	}
	else
	{
		button.innerHTML = button.innerHTML.replace('View','Hide');
		$('reviewsContainer').style.display='';
	}
	
}
/**
 * returnXhrRequestFromFormStr
 * @param element (dom element)
 * @return string 
 * @TODO: add support for radio buttons
 */
function returnXhrRequestFromFormStr(element)
{	
	if(typeof(element)=='string'){
		element = $(element);
	}
	
    var len = element.elements.length;
	var str = '';
	
    for (var i = 0; i < len; i++) 
	{
		var e = element.elements[i];

       	if(e.id != '' && e.id != undefined)
		{
			if(e.type == 'text'){ // text elements
				str+= '&'+e.id+'='+encodeURI(escape(e.value));
			}
			else if(e.type=='checkbox' && e.checked==true){ // checkbox is checked 
				str+= '&'+e.id+'=1';
			}
			else if(e.type=='checkbox' && e.checked==false){  // checkbox is not checked 
				str+= '&'+e.id+'=0';
			}
			else if(e.type=='radio' && e.checked==true)
			{
				str+= '&'+e.name+'='+encodeURI(escape(e.value));
			}
			else if(e.type=='select-one') // select values should also include selectedIndexes text
			{ 
				var index = $(e.id).selectedIndex;
				if(index != -1){
					str+= '&'+e.id+'_text='+encodeURI(escape(e.options[index].text));
					str+= '&'+e.id+'='+encodeURI(escape(e.value));
				}
			}
			else if(e.type=='select-multiple') // multiple select
			{
				var valueArr = new Array();
				var textArr = new Array();
				for(var j=0;j<e.length;j++){
					if(e.options[j].selected==true){
						valueArr.push(encodeURI(escape(e.options[j].value)));
						textArr.push(encodeURI(escape(e.options[j].text)));
					}
				}
				str+='&'+e.id+'_jsonValue='+JSON.encode(valueArr);
				str+='&'+e.id+'_jsonText='+JSON.encode(textArr);
			}
			else{ // all other elements 
				str+= '&'+e.id+'='+encodeURI(escape(e.value));
			}
        }
    }
	
	return str;
}
function url_encode(string)
{
	return encodeURIComponent(string).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/%20/g, '+')
}