if(typeof this['COMMENT_FUNCTIONS_LOADED'] == 'undefined') {
	
	var visitorCommentHeaderTemplate = new Template('#{start} to #{end} of #{count} comment');
	var commentsTotal = 0;
	var commentsCurrentPage = 0;
	var commentsCurrentPostId = 0;
	var commentsStartAt = 0; // which comment currently starting from
	var commentsPerPage = 10; // number of comments per page
	var commentsGroupSize = 5;	// number of pages to display in each group 
	var commentNavigationCount = 0;
	var totalPages = 0;
	
	function getComments(startAt, postId) {
		totalPages = Math.ceil(commentsTotal/commentsPerPage);
		
		if(startAt == 'LAST_PAGE') {
			commentsStartAt = (totalPages-1)*commentsPerPage + 1;
		} else {
			commentsStartAt = startAt;
		}
		if (commentsStartAt < 0) commentsStartAt = 0;
		if(postId)
			commentsCurrentPostId = postId;
	
		CommentManager.getComments(commentsCurrentPostId, commentsStartAt-1, commentsPerPage, {callback: getCommentsCallback});
	}
	
	function getCommentsCallback(returnVal, args) {
	
		//RMI Changes commentsTotal = returnVal.totalSize;
		commentsTotal = returnVal.totalSize;
		commentsCurrentPage = Math.ceil(commentsStartAt / commentsPerPage);
		totalPages = Math.ceil(commentsTotal/commentsPerPage);
		//RMI var comments = returnVal.entries;
		var comments = returnVal.comments;
		
		// clear the comments
		$('visitorComments').update();
	
		// update the header
		var visitorCommentsHeader = Builder.node('h4', { className: 'breaker', style: 'margin-top: 0px' }, 'There are no comments' );
		$('visitorComments').insert(visitorCommentsHeader);
		if(commentsTotal > 0) {
			if (commentsStartAt == 0) commentsStartAt = 1;
			visitorCommentsHeader.update(
				visitorCommentHeaderTemplate.evaluate( {
					start: commentsStartAt,
					end: Math.min((+commentsStartAt)+(+commentsPerPage)-1, commentsTotal),
					count: commentsTotal
				} ));
			if(commentsTotal>1) visitorCommentsHeader.insert('s');
			$('visitorComments').insert(buildNavigation());
		}
	
		// add the comments
		comments.each( function(comment){
			$('visitorComments').appendChild(buildCommentHTML(comment))
		});
	
		// add the footer
		if(commentsTotal > 0) {
			$('visitorComments').insert(buildNavigation('commentFooter'));
		}
	}
	
	function getElementsByClassName(classname, node)  {    
		if(!node) node = document.getElementsByTagName("body")[0];    
		var a = [];    
		var re = new RegExp('\\b' + classname + '\\b');    
		var els = node.getElementsByTagName("*");    
		for(var i=0,j=els.length; i<j; i++)        
			if(re.test(els[i].className))
				a.push(els[i]);    
		return a;
	}
	
	function postComment() {
	
		// stop multi clicking buttons until callback called
		$('windowDimmer').style.height = (getViewportScrollY()+getViewportHeight())+'px';
		$('windowDimmer').style.width = '100%';
		$('windowDimmer').style.display = 'block';
		
		// clear all old validation messages
		$$('span.cmtFrmValErr').each(Element.remove);
	
		// make sure tinymce editor has posted content to textarea
		tinyMCE.triggerSave(true, true);
	
		var entryId = Number(dwr.util.getValue('entryID'));
		var commenterId = Number(dwr.util.getValue('commenterID'));
		if(isNaN(commenterId)) commenterId = undefined;
		
		var memberType = dwr.util.getValue('memberType');
		var name = dwr.util.getValue('commentName');
		var url = dwr.util.getValue('commentURL');
		var email = dwr.util.getValue('commentEmail');
		var profileImage = dwr.util.getValue('profileImage');
		var image = '';
		if(profileImage=='Upload')
			var image = dwr.util.getValue('commentFile');
		
		var commentText = dwr.util.getValue('commentText');
	
		var wordVerification = dwr.util.getValue('wordVerification');
		var legacyUsed = dwr.util.getValue('legacyUsed');
		var recaptchaChallengeField = dwr.util.getValue('recaptcha_challenge_field');
		var recaptchaResponseField = dwr.util.getValue('recaptcha_response_field');
		
		CommentManager.addComment(entryId, commenterId,
			memberType, name, url, email, profileImage, image, commentText,
			wordVerification, legacyUsed, recaptchaChallengeField, recaptchaResponseField,
			{callback:postCommentCallback});
	}
	
	function postCommentCallback(arg) {
		if(arg.errors) {
			for(var key in arg.errors) {
				// cmtFrmValErr is a dummy class so that we can easily retrieve these nodes with prototype
				var errorNode = Builder.node(
					'span',
					{ className: 'small error cmtFrmValErr' },
					arg.errors[key].replace(/<[^>]*>/g, '')
				);
				if(key=='GLOBAL') {
					$('leaveCommentTitle').insert({after: errorNode});
				} else if(key=='wordVerification') {
					// special case for captcha or error ends up in hidden div
					$('legacy_captcha').insert({before: errorNode});
				} else {
					// insert error before element with same id as error key
					// or swallow if no such element
					var element = $(key);
					if(element)
						element.insert({before: errorNode});
				}
			}
			
			// reenable clicks
			$('windowDimmer').style.display = 'none';
		} else {
			// clear the captchas
			try {
				if(typeof Recaptcha != 'undefined')	Recaptcha.reload ();
			} catch (e){
				// ignore. if the captcha didn't clear we don't care (too much)
			}
			try {
				$('wordVerification').update();
			} catch (e){
				// ignore. if the captcha didn't clear we don't care (too much)
			}
			// increment commentsTotal, could be more posted in the meantime but we know of at least 1
			++commentsTotal;
			// go to last page of comments
			getComments('LAST_PAGE');
			// wait a second for posts to be populated because we are calling them asychronously
			setTimeout(postCommentRemoveDimmer, 1000);
		}
		
	}
	
	function postCommentRemoveDimmer() {
		// reenable clicks
		$('windowDimmer').style.display = 'none';
		
		// jump to post
		var offset = $('commentFooter').cumulativeOffset();
		self.scrollTo(0, offset.top - document.viewport.getHeight() + $('commentFooter').getHeight());
	}
	
	function deleteComment(url) {
		if(confirm('Do you want to delete comment?')) {
		  location = url;
		}
	}
	
	function buildCommentHTML(comment) {
		var frag = document.createDocumentFragment();
	
		var header = Builder.node('h5', {className:'commenterName'});
		if (comment.commenterID) {
			header.addClassName('h5_BBMember');
		}
		if (comment.email) {
			var email = Builder.node('a', {href:'mailto:' + comment.email + '&subject=' + comment.name}, comment.name);
			header.insert(email);
		} else {
		    header.insert(comment.name);
		}
		var post = Builder.node('div', {className:'blogOutput noflow'}, Builder.node('p', {className:'postSubHead small t8px'}, comment.createDate.toLocaleString()));
		if (comment.url) {
			post.appendChild(Builder.node('p', {className:'postSubHead small t8px'}, Builder.node('a', {href:'javascript:void window.open(\'' + comment.url + '\');'}, comment.url)));
		}
		if (comment.attachedItem) {
			post.appendChild(Builder.node('span', {className:'commentAvatar'}, 
				Builder.node('img', {
					src: comment.attachedItem.thumbInfo.path,
					width: comment.attachedItem.thumbInfo.width,
					height: comment.attachedItem.thumbInfo.height,
					border:0
				})
			));
		}
		post.appendChild(Builder.node('div').update(comment.comment));
		post.appendChild(Builder.node('div', {className:'c1'}));
	
		if(owner && owner.length > 0) {
			var deleteButton = Builder.node('div', { className: 'hidden' });
			var buttonDiv = Builder.node('div', { className: 'blogbutton' });
			var anchor = Builder.node('a', { 
						href: 'javascript:deleteComment(\'/comment.do?type=delete&entryID=' + comment.entryID + '&commentID=' + comment.commentID + '\')',
						className: 'button',
						style: 'display: inline'});
			$(anchor).insert('Delete Comment');
			$(buttonDiv).insert(anchor);
			$(deleteButton).insert(buttonDiv);
		}
		
		frag.appendChild(header);
		frag.appendChild(post);
		if(deleteButton) frag.appendChild(deleteButton);
		frag.appendChild(Builder.node('hr'));
		
		return frag;
	}
	
	// see rt8663 for requirements of navigation
	function buildNavigation(navId) {
		if(!navId || navId=='')
			navId = 'commentNavigation' + (++commentNavigationCount);
		var nav = Builder.node('h4', { id: navId, className: 'breaker', style: 'text-align:center' });
		
		// the page number of the page at the end of the displayed group
		var endGroupPage = Math.ceil(commentsCurrentPage/commentsGroupSize)*commentsGroupSize;
		// the page number of the page at the start of the displayed group
		var startGroupPage = endGroupPage-commentsGroupSize+1;
		// the post number at the start of the last page
		var lastPageStart = (totalPages-1)*commentsPerPage + 1;
		// the post number at the start of the page of the last page of the previous group
		var prevGroupStart = ((endGroupPage-commentsGroupSize)-1)*commentsPerPage+1;
		// the post number of the start of the page of the first page of the next group
		var nextGroupStart = endGroupPage*commentsPerPage+1;
	
		var backNav = Builder.node('span', { style: 'float:left' });
	
		// first page link
		var anchor = Builder.node('a', '<< first');
		anchor.insert('&nbsp;');
		if(commentsCurrentPage > 1)
			anchor.href = 'javascript:getComments(1)';
		else
			anchor.style.textDecoration = 'none';
		backNav.insert( anchor );
		
		// previous group link
		anchor = Builder.node('a', '< previous');
		if(prevGroupStart > 1)
			anchor.href = 'javascript:getComments(' + prevGroupStart + ')';
		else
			anchor.style.textDecoration = 'none';
		backNav.insert( anchor );
		
		// page links
		var middleNav = Builder.node('span');
		for(var page = Math.max(1, startGroupPage); page <= Math.min(totalPages, endGroupPage); page++) {
			if( page==commentsCurrentPage )
				middleNav.insert( Builder.node('b', { style: 'font-size: larger' }, page) );
			else
				middleNav.insert( Builder.node('a', { href: 'javascript:getComments(' + ((page-1)*commentsPerPage+1) + ')' }, page) );
			
			if( page != Math.min(totalPages, endGroupPage) ) middleNav.insert( '&nbsp;' );
		}
		
		var forwardNav = Builder.node('span', { style: 'float:right' });
		
		// next group link
		anchor = Builder.node('a', 'next >');
		anchor.insert('&nbsp;');
		if(commentsCurrentPage < totalPages)
			anchor.href = 'javascript:getComments(' + Math.min(lastPageStart, nextGroupStart) + ')';
		else
			anchor.style.textDecoration = 'none';
		forwardNav.insert( anchor );
		
		// last page link
		anchor = Builder.node('a', 'last >>');
		if(commentsCurrentPage < totalPages)
			anchor.href = 'javascript:getComments(' + lastPageStart + ')';
		else
			anchor.style.textDecoration = 'none';
		forwardNav.insert( anchor );
		
		// put it together
		nav.insert(backNav);
		nav.insert(forwardNav);
		nav.insert(middleNav);
	
		return nav;	
	}
	
	this.COMMENT_FUNCTIONS_LOADED = true;
}