function showLoginForm() {
	if (!winFormLogin) {
		winFormLogin=new StickyWinModal({content: $('login-form-content').get('html'), closeClassName: 'close-block'});
	}
	winFormLogin.show();
	winFormLogin.pin(true);
}

function hideLoginForm() {
	winFormLogin.hide();
}

var winFormLogin=false;

var lsVote;

var lsVoteClass = new Class({

        Implements: Options,

        options: {
                classes_action: {
                        voted:          'voted',
                        plus:           'plus',
                        minus:          'minus',
                        positive:       'positive',
                        negative:       'negative',
                        quest:          'quest'
                },
                classes_element: {
                        voting:         'voting',
                        count:          'count',
                        total:          'total',
                        plus:           'plus',
                        minus:          'minus'
                }
        },

        typeVote: {
                topic_comment: {
                        url: DIR_WEB_ROOT+'/include/ajax/voteComment.php',
                        targetName: 'idComment'
                },
                topic: {
                        url: DIR_WEB_ROOT+'/include/ajax/voteTopic.php',
                        targetName: 'idTopic'
                },
                blog: {
                        url: DIR_WEB_ROOT+'/include/ajax/voteBlog.php',
                        targetName: 'idBlog'
                },
                user: {
                        url: DIR_WEB_ROOT+'/include/ajax/voteUser.php',
                        targetName: 'idUser'
                }
        },

        initialize: function(options){
                this.setOptions(options);
        },

        vote: function(idTarget,objVote,value,type) {
                if (!this.typeVote[type]) {
                        return false;
                }

                this.idTarget=idTarget;
                this.objVote=$(objVote);
                this.value=value;
                this.type=type;
                thisObj=this;

                var params = new Hash();
                params['value']=value;
                params[this.typeVote[type].targetName]=idTarget;

                JsHttpRequest.query(
                        this.typeVote[type].url,
                        params,
                        function(result, errors) {
                                thisObj.onVote(result, errors, thisObj);
                        },
                        true
                );
        },

        onVote: function(result, errors, thisObj) {
        	if (!result) {
                msgErrorBox.alert('Error','Please try again later');
        	}
        	if (result.bStateError) {
                msgErrorBox.alert(result.sMsgTitle,result.sMsg);
        	} else {
                msgNoticeBox.alert(result.sMsgTitle,result.sMsg);

                var divVoting=thisObj.objVote.getParent('.'+thisObj.options.classes_element.voting);
                divVoting.addClass(thisObj.options.classes_action.voted);

                if (this.value>0) {
                        divVoting.addClass(thisObj.options.classes_action.plus);
                }
                if(this.value<0) {
                        divVoting.addClass(thisObj.options.classes_action.minus);
                }
                var divCount=divVoting.getChildren('.'+thisObj.options.classes_element.count);
                if (divCount && divCount[0]) {
                	divCount.set('text',result.iCountVote);
                }

                var divTotal=divVoting.getChildren('.'+thisObj.options.classes_element.total);
                result.iRating=parseFloat(result.iRating);
                divVoting.removeClass(thisObj.options.classes_action.negative);
                divVoting.removeClass(thisObj.options.classes_action.positive);
                if (result.iRating>0) {
                        divVoting.addClass(thisObj.options.classes_action.positive);
                        divTotal.set('text','+'+result.iRating);
                }
                if (result.iRating<0) {
                        divVoting.addClass(thisObj.options.classes_action.negative);
                        divTotal.set('text',result.iRating);
                }
                if (result.iRating==0) {
                        divTotal.set('text','0');
                }

                if (thisObj.type=='user' && $('user_skill_'+thisObj.idTarget)) {
                	$('user_skill_'+thisObj.idTarget).set('text',result.iSkill);
                }
        	}
        }

});

window.addEvent('domready', function() {
      lsVote=new lsVoteClass();
});

var lsBlockLoaderClass = new Class({

        Implements: Options,

        options: {
        		classes_nav: {
        				nav: 	 'block-nav',
        				content: 'block-content',
                        active:  'active'
                }
        },

        type: {
                comment_stream: {
                        url: DIR_WEB_ROOT+'/include/ajax/stream_comment.php'
                },
                topic_stream: {
                        url: DIR_WEB_ROOT+'/include/ajax/stream_topic.php'
                },
                blogs_top: {
                        url: DIR_WEB_ROOT+'/include/ajax/blogs_top.php'
                },
                blogs_join: {
                        url: DIR_WEB_ROOT+'/include/ajax/blogs_join.php'
                },
                blogs_self: {
                        url: DIR_WEB_ROOT+'/include/ajax/blogs_self.php'
                }
        },

        initialize: function(options){
                this.setOptions(options);
        },

        toggle: function(obj,type,params) {
        	if (!this.type[type]) {
            	return false;
            }
            thisObj=this;
            this.obj=$(obj);

            var liCurrent=thisObj.obj.getParent('li');
            var blockNav=liCurrent.getParent('ul.'+thisObj.options.classes_nav.nav);
            var liList=blockNav.getChildren('li');

            liList.each(function(li,index) {
            	li.removeClass(thisObj.options.classes_nav.active);
        	});

        	liCurrent.addClass(this.options.classes_nav.active);

        	var blockContent=blockNav.getParent('div').getChildren('div.'+this.options.classes_nav.content)[0].set('html','');
        	this.showStatus(blockContent);


            JsHttpRequest.query(
            	this.type[type].url,
                params,
                function(result, errors) {
                	thisObj.onLoad(result, errors, blockContent);
                },
                true
            );

		},

		onLoad: function(result, errors, blockContent) {
			blockContent.set('html','');
			if (!result) {
                msgErrorBox.alert('Error','Please try again later');
        	}
        	if (result.bStateError) {
                //msgErrorBox.alert(result.sMsgTitle,result.sMsg);
        	} else {
        		blockContent.set('html',result.sText);
        	}
		},

		showStatus: function(obj) {
			var newDiv = new Element('div');
			newDiv.setStyle('text-align','center');
			newDiv.set('html','<img src="'+DIR_STATIC_SKIN+'/images/loader.gif" >');

			newDiv.inject(obj);
		}
});

function ajaxJoinLeaveBlog(obj,idBlog) {
	obj=$(obj);
	JsHttpRequest.query(
    	DIR_WEB_ROOT+'/include/ajax/joinLeaveBlog.php',
        { idBlog: idBlog },
        function(result, errors) {
        	if (!result) {
                msgErrorBox.alert('Error','Please try again later');
        	}
            if (result.bStateError) {
            	msgErrorBox.alert(result.sMsgTitle,result.sMsg);
            } else {
            	msgNoticeBox.alert(result.sMsgTitle,result.sMsg);
            	if (obj)  {
            		obj.getParent().removeClass('active');
            		if (result.bState) {
            			obj.getParent().addClass('active');
            		}
            		divCount=$('blog_user_count_'+idBlog);
            		if (divCount) {
            			divCount.set('text',result.iCountUser);
            		}
            	}
            }
        },
        true
    );
}


function ajaxBlogInfo(idBlog) {
	JsHttpRequest.query(
    	DIR_WEB_ROOT+'/include/ajax/blogInfo.php',
        { idBlog: idBlog },
        function(result, errors) {
        	if (!result) {
                msgErrorBox.alert('Error','Please try again later');
        	}
            if (result.bStateError) {

            } else {
            	if ($('block_blog_info')) {
            		$('block_blog_info').set('html',result.sText);
            	}
            }
        },
        true
    );
}

var lsCmtTreeClass = new Class({

	Implements: Options,

	options: {
		img: {
			path: 		'images/',
			openName:  	'open.gif',
			closeName: 	'close.gif'
		},
		classes: {
			visible: 	'lsCmtTree_visible',
			hidden:  	'lsCmtTree_hidden',
			openImg:  	'lsCmtTree_open',
			closeImg:  	'lsCmtTree_close'
		}
	},

	initialize: function(options){
		this.setOptions(options);
		this.make();
		this.aCommentNew=[];
		this.iCurrentShowFormComment=0;
		this.iCommentIdLastView=null;
		this.countNewComment=0;
		this.docScroller = new Fx.Scroll(document.getDocument());
		this.hideCommentForm(this.iCurrentShowFormComment);
	},

	make: function(){
		var thisObj = this;
		var aImgFolding=$$('img.folding');
		aImgFolding.each(function(img, i){
			var divComment = img.getParent('div').getChildren('div.comment-children')[0];
			if (divComment && divComment.getChildren('div.comment')[0]) {
				thisObj.makeImg(img);
			} else {
				img.setStyle('display','none');
			}
		});
	},

	makeImg: function(img) {
		var thisObj = this;
		img.setStyle('cursor', 'pointer');
		img.setStyle('display','inline');
		img.addClass(this.options.classes.closeImg);
		img.removeEvents('click');
		img.addEvent('click',function(){
			thisObj.toggleNode(img);
		});
	},

	toggleNode: function(img) {
		var b = img.hasClass(this.options.classes.closeImg);
		if (b) {
			this.collapseNode(img);
		} else {
			this.expandNode(img);
		}
	},

	expandNode: function(img) {
		var thisObj = this;
		img.setProperties({'src': this.options.img.path + this.options.img.closeName});
		img.removeClass(this.options.classes.openImg);
		img.addClass(this.options.classes.closeImg);
		var divComment = img.getParent('div').getChildren('div.comment-children')[0];

		divComment.removeClass(thisObj.options.classes.hidden);
		divComment.addClass(thisObj.options.classes.visible);
	},

	collapseNode: function(img) {
		var thisObj = this;
		img.setProperties({'src': this.options.img.path + this.options.img.openName});
		img.removeClass(this.options.classes.closeImg);
		img.addClass(this.options.classes.openImg);
		var divComment = img.getParent('div').getChildren('div.comment-children')[0];

		divComment.removeClass(thisObj.options.classes.visible);
		divComment.addClass(thisObj.options.classes.hidden);
	},

	expandNodeAll: function() {
		var thisObj = this;
		var aImgFolding=$$('img.'+this.options.classes.openImg);
		aImgFolding.each(function(img, i){
			thisObj.expandNode(img);
		});
	},

	collapseNodeAll: function() {
		var thisObj = this;
		var aImgFolding=$$('img.'+this.options.classes.closeImg);
		aImgFolding.each(function(img, i){
			thisObj.collapseNode(img);
		});
	},

	injectComment: function(idCommentParent,idComment,sHtml) {
		var newComment = new Element('div',{'class':'comment', 'id': 'comment_id_'+idComment});
		newComment.set('html',sHtml);
		if (idCommentParent) {
			this.expandNodeAll();
			var divChildren = $('comment-children-'+idCommentParent);
			var imgParent = divChildren.getParent('div').getChildren('img.folding')[0];
			this.makeImg(imgParent);
			divChildren.appendChild(newComment);
		} else {
			var divChildren = $('comment-children-0');
			newComment.inject(divChildren,'before');
		}
	},

	responseNewComment: function(idTopic,objImg,selfIdComment,bNotFlushNew) {
		var thisObj=this;

		if (!bNotFlushNew) {
			var aDivComments=$$('.comment');
			aDivComments.each(function(item,index){
				var divContent=item.getChildren('div.content')[0];
				if (divContent) {
					divContent.removeClass('new');
					divContent.removeClass('view');
				}
			});
		}
		var idCommentLast=this.idCommentLast;
		objImg=$(objImg);
		objImg.setProperty('src',DIR_STATIC_SKIN+'/images/update_act.gif');
		(function(){
		JsHttpRequest.query(
        	DIR_WEB_ROOT+'/include/ajax/commentResponse.php',
        	{ idCommentLast: idCommentLast, idTopic: idTopic },
        	function(result, errors) {
        		objImg.setProperty('src',DIR_STATIC_SKIN+'/images/update.gif');
            	if (!result) {
                	msgErrorBox.alert('Error','Please try again later');
        		}
        		if (result.bStateError) {
                	msgErrorBox.alert(result.sMsgTitle,result.sMsg);
        		} else {
        			var aCmt=result.aComments;
        			if (aCmt.length>0 && result.iMaxIdComment) {
        				thisObj.setIdCommentLast(result.iMaxIdComment);
        				var countComments=$('count-comments');
        				countComments.set('text',parseInt(countComments.get('text'))+aCmt.length);
        				if ($('block_stream_comment') && lsBlockStream) {
        					lsBlockStream.toggle($('block_stream_comment'),'comment_stream');
        				}
        			}
        			var iCountOld=0;
        			if (bNotFlushNew) {
        				iCountOld=thisObj.countNewComment;
        			} else {
        				thisObj.aCommentNew=[];
        			}
        			if (selfIdComment) {
        				thisObj.setCountNewComment(aCmt.length-1+iCountOld);
        				thisObj.hideCommentForm(thisObj.iCurrentShowFormComment);
        			} else {
        				thisObj.setCountNewComment(aCmt.length+iCountOld);
        			}
        			aCmt.each(function(item,index) {
        				if (!(selfIdComment && selfIdComment==item.id)) {
        					thisObj.aCommentNew.extend([item.id]);
        				}
        				thisObj.injectComment(item.idParent,item.id,item.html);
        			});

        			if (selfIdComment && $('comment_id_'+selfIdComment)) {
						thisObj.scrollToComment(selfIdComment);
					}
        		}
	        },
        	true
       );
       }).delay(1000);
	},

	setIdCommentLast: function(id) {
		this.idCommentLast=id;
	},

	setCountNewComment: function(count) {
		this.countNewComment=count;
		var divCountNew=$('new-comments');
        if (this.countNewComment>0) {
        	divCountNew.set('text',this.countNewComment);
        	divCountNew.setStyle('display','block');
        } else {
        	this.countNewComment=0;
        	divCountNew.set('text',0);
        	divCountNew.setStyle('display','none');
        }
	},

	goNextComment: function() {
		if (this.aCommentNew[0]) {
			if ($('comment_id_'+this.aCommentNew[0])) {
				this.scrollToComment(this.aCommentNew[0]);
			}
			this.aCommentNew.erase(this.aCommentNew[0]);
		}
		this.setCountNewComment(this.countNewComment-1);
	},

	scrollToComment: function(idComment) {
		this.docScroller.setOptions({
			duration:500,
			offset: {
        		'x': 0,
        		'y': 0
   			}
 		});
		this.docScroller.start(0,$('comment_id_'+idComment).getPosition().y-window.getSize().y/2);
		if (this.iCommentIdLastView) {
			$('comment_content_id_'+this.iCommentIdLastView).removeClass('view');
		}
		$('comment_content_id_'+idComment).addClass('view');
		this.iCommentIdLastView=idComment;
	},

	addComment: function(formObj,topicId) {
		var thisObj=this;
		cmt_topic_id = $('cmt_topic_id').get('value');
		reply = $('form_comment_reply').get('value');
		text = $('form_comment_text').get('value');
		JsHttpRequest.query(
        	DIR_WEB_ROOT+'/include/ajax/commentAdd.php',
        	{ cmt_topic_id: cmt_topic_id, reply: reply, comment_text: text },
        	function(result, errors) {
            	if (!result) {
            		thisObj.enableFormComment();
                	msgErrorBox.alert('Error','Please try again later');
        		}
        		if (result.bStateError) {
					thisObj.enableFormComment();
                	msgErrorBox.alert(result.sMsgTitle,result.sMsg);
        		} else {
        			$('form_comment_text').disabled=true;
        			thisObj.responseNewComment(topicId,$('update-comments'),result.sCommentId,true);
        		}
	        },
        	true
      	);

      	//$('form_comment_text').addClass('loader');
	},

	enableFormComment: function() {
		$('form_comment_text').removeClass('loader');
		$('form_comment_text').disabled=false;
	},

	addCommentScroll: function(commentId) {
		this.aCommentNew.extend([commentId]);
		this.setCountNewComment(this.countNewComment+1);
	},

	toggleComment: function(obj,commentId) {
		var divContent=$('comment_content_id_'+commentId);
		if (!divContent) {
			return false;
		}

		var thisObj=this;
		JsHttpRequest.query(
        	DIR_WEB_ROOT+'/include/ajax/commentToggle.php',
        	{ idComment: commentId },
        	function(result, errors) {
            	if (!result) {
                	msgErrorBox.alert('Error','Please try again later');
        		}
        		if (result.bStateError) {
                	msgErrorBox.alert(result.sMsgTitle,result.sMsg);
        		} else {
        			msgNoticeBox.alert(result.sMsgTitle,result.sMsg);
        			divContent.removeClass('old').removeClass('self').removeClass('new').removeClass('del');
        			obj.removeClass('delete').removeClass('repair');
        			if (result.bState) {
        				divContent.addClass('del');
        				obj.addClass('repair');
        			} else {
        				obj.addClass('delete');
        			}
					obj.set('text',result.sTextToggle);
        		}
	        },
        	true
       );
	},

	toggleCommentForm: function(idComment) {
		if (!$('reply_'+this.iCurrentShowFormComment) || !$('reply_'+idComment)) {
			return;
		}
		divCurrentForm=$('reply_'+this.iCurrentShowFormComment);
		divNextForm=$('reply_'+idComment);

		var slideCurrentForm = new Fx.Slide(divCurrentForm);
		var slideNextForm = new Fx.Slide(divNextForm);

		$('comment_preview_'+this.iCurrentShowFormComment).set('html','').setStyle('display','none');
		if (this.iCurrentShowFormComment==idComment) {
			slideCurrentForm.toggle();
			//$('form_comment_text').focus();
			return;
		}

		slideCurrentForm.slideOut();
		divNextForm.set('html',divCurrentForm.get('html'));
		divCurrentForm.set('html','');
		divNextForm.setStyle('display','block');
		slideNextForm.hide();

		slideNextForm.slideIn();

		//$('form_comment_text').focus();
		$('form_comment_text').setProperty('value','');
		$('form_comment_reply').setProperty('value',idComment);
		this.iCurrentShowFormComment=idComment;
	},

	hideCommentForm: function(idComment) {
		if ($('reply_'+idComment)) {
			this.enableFormComment();
			$('comment_preview_'+this.iCurrentShowFormComment).set('html','').setStyle('display','none');
			var slideForm = new Fx.Slide('reply_'+idComment);
			slideForm.hide();
		}
	},

	preview: function() {
		ajaxTextPreview('form_comment_text',false,'comment_preview_'+this.iCurrentShowFormComment);
	},

	goToParentComment: function(obj) {
		var idCmt = obj.href.substr(obj.href.indexOf('#')+8);
		var objCmtParent=$('comment_id_'+idCmt);
		var objCmt=obj.getParent('div.comment');
		objCmtParent.getElement('.goto-comment-child').removeClass('hidden');
		objCmtParent.getElement('.goto-comment-child a').href = '#comment' + objCmt.id.substr(11);
		this.docScroller.setOptions({
			offset: {'y': 0}
 		});
		this.docScroller.toElement(objCmtParent);
		return false;
	},

	goToChildComment: function(obj) {
		var idCmt = obj.href.substr(obj.href.indexOf('#')+8);
		var objCmtChild=$('comment_id_'+idCmt);
		var objCmt=obj.getParent('div.comment');
		objCmt.getElement('.goto-comment-child').addClass('hidden');
		this.docScroller.setOptions({
			offset: {'y': 0}
 		});
		this.docScroller.toElement(objCmtChild);
		return false;
	}
});


var lsCmtTree;
var formCommentSlide;

window.addEvent('domready', function() {
    lsCmtTree = new lsCmtTreeClass({
    	img: {
    		path: DIR_STATIC_SKIN+'/images/'
    	},
    	classes: {
    		openImg: 'folding-open',
    		closeImg: 'folding'
    	}
    });
});

var lsFavourite;

var lsFavouriteClass = new Class({

        Implements: Options,

        options: {
                classes_action: {
                        active:    'active',
                        quest:     'quest'
                },
                classes_element: {
                        favorite:  'favorite'
                }
        },

        typeFavourite: {
                topic: {
                        url: DIR_WEB_ROOT+'/include/ajax/topicFavourite.php',
                        targetName: 'idTopic'
                }
        },

        initialize: function(options){
                this.setOptions(options);
        },

        toggle: function(idTarget,objFavourite,type) {
                if (!this.typeFavourite[type]) {
                        return false;
                }

                this.idTarget=idTarget;
                this.objFavourite=$(objFavourite);
                this.value=value;
                this.type=type;
                thisObj=this;

                var value=1;
                if (this.objFavourite.getParent('.'+this.options.classes_element.favorite).hasClass(this.options.classes_action.active)) {
                	value=0;
                }

                var params = new Hash();
                params['type']=value;
                params[this.typeFavourite[type].targetName]=idTarget;

                JsHttpRequest.query(
                        this.typeFavourite[type].url,
                        params,
                        function(result, errors) {
                                thisObj.onToggle(result, errors, thisObj);
                        },
                        true
                );
        },

        onToggle: function(result, errors, thisObj) {
        	if (!result) {
                msgErrorBox.alert('Error','Please try again later');
        	}
        	if (result.bStateError) {
                msgErrorBox.alert(result.sMsgTitle,result.sMsg);
        	} else {
                msgNoticeBox.alert(result.sMsgTitle,result.sMsg);

                var divFavourite=thisObj.objFavourite.getParent('.'+thisObj.options.classes_element.favorite);
                divFavourite.removeClass(thisObj.options.classes_action.active);
                if (result.bState) {
                	divFavourite.addClass(thisObj.options.classes_action.active);
                }
        	}
        }

});

window.addEvent('domready', function() {
      lsFavourite=new lsFavouriteClass();
});

function ajaxToggleUserFrend(obj,idUser) {
	obj=$(obj);
	JsHttpRequest.query(
    	DIR_WEB_ROOT+'/include/ajax/userFriend.php',
        { idUser: idUser },
        function(result, errors) {
        	if (!result) {
                msgErrorBox.alert('Error','Please try again later');
        	}
            if (result.bStateError) {
            	msgErrorBox.alert(result.sMsgTitle,result.sMsg);
            } else {
            	msgNoticeBox.alert(result.sMsgTitle,result.sMsg);
            	if (obj)  {
            		obj.set('text',result.sToggleText);
            		if (result.bState) {
            			obj.getParent('li').removeClass('add');
            			obj.getParent('li').addClass('del');
            		} else {
            			obj.getParent('li').removeClass('del');
            			obj.getParent('li').addClass('add');
            		}
            	}
            }
        },
        true
    );
}function ajaxTextPreview(textId,save,divPreview) {
	var text;
	if (BLOG_USE_TINYMCE && tinyMCE && (ed=tinyMCE.get(textId))) {
		text = ed.getContent();
	} else {
		text = $(textId).value;
	}
	JsHttpRequest.query(
    	DIR_WEB_ROOT+'/include/ajax/textPreview.php',
        { text: text, save: save },
        function(result, errors) {
        	if (!result) {
                msgErrorBox.alert('Error','Please try again later');
        	}
            if (result.bStateError) {
            	msgErrorBox.alert('Error','Please try again later');
            } else {
            	if (!divPreview) {
            		divPreview='text_preview';
            	}
            	if ($(divPreview)) {
            		$(divPreview).set('html',result.sText).setStyle('display','block');
            	}
            }
        },
        true
    );
}


// для опроса
function addField(btn){
        tr = btn;
        while (tr.tagName != 'TR') tr = tr.parentNode;
        var newTr = tr.parentNode.insertBefore(tr.cloneNode(true),tr.nextSibling);
        checkFieldForLast();
}
function checkFieldForLast(){
        btns = document.getElementsByName('drop_answer');
        for (i = 0; i < btns.length; i++){
        	btns[i].disabled = false;
        }
        if (btns.length<=2) {
        	btns[0].disabled = true;
        	btns[1].disabled = true;
        }
}
function dropField(btn){
        tr = btn;
        while (tr.tagName != 'TR') tr = tr.parentNode;
        tr.parentNode.removeChild(tr);
        checkFieldForLast();
}



function checkAllTalk(checkbox) {
	$$('.form_talks_checkbox').each(function(chk){
		if (checkbox.checked) {
			chk.checked=true;
		} else {
			chk.checked=false;
		}
	});
}


function showImgUploadForm() {
	if (!winFormImgUpload) {
		winFormImgUpload=new StickyWinModal({content: $('uploadimg-form-content').get('html'), closeClassName: 'close-block'});
	}
	winFormImgUpload.show();
	winFormImgUpload.pin(true);

}

function hideImgUploadForm() {
	winFormImgUpload.hide();
}

var winFormImgUpload;

window.addEvent('domready', function() {
	var form=$('window_load_img');
	if (form) {
		form.setStyle('display','block');
    	winFormImgUpload=new StickyWinModal({content: form, closeClassName: 'close-block'});
    	winFormImgUpload.pin(true);
    	winFormImgUpload.hide();
	}
});


function ajaxUploadImg(value,sToLoad) {
	sToLoad=$(sToLoad);
	var req = new JsHttpRequest();
	req.onreadystatechange = function() {
		if (req.readyState == 4) {
			if (req.responseJS.bStateError) {
				msgErrorBox.alert('Ошибка','Возникли проблемы при загрузке изображения, попробуйте еще разок. И на всякий случай проверьте правильность URL картинки');
			} else {
				sToLoad.insertAtCursor(req.responseJS.sText);
				hideImgUploadForm();
			}
		}
	}
	req.open(null, DIR_WEB_ROOT+'/include/ajax/uploadImg.php', true);
	req.send( { value: value } );
}
var lsPanelClass = new Class({
	initialize: function(){

	},

	putText: function(obj,text) {
		obj=$(obj);
		obj.insertAtCursor(text);
	},

	putTag: function(obj,tag) {
		this.putText(obj,'<'+tag+'/>');
	},

	putTextAround: function(obj,textStart,textEnd) {
		obj=$(obj);
		obj.insertAroundCursor({
			before: textStart,
			defaultMiddle: '',
			after: textEnd
		});
	},

	putTagAround: function(obj,tagStart,tagEnd) {
		if (!tagEnd) {
			tagEnd=tagStart;
		}
		this.putTextAround(obj,'<'+tagStart+'>','</'+tagEnd+'>');
	},

	putTagUrl: function(obj,sPromt) {
		obj=$(obj);
		if (url=prompt(sPromt,'http://')) {
			var sel=obj.getSelectedText();
        	this.putText(obj,'<a href="'+url+'">'+sel+'</a>');
        }
	}
});

var lsPanel;

window.addEvent('domready', function() {
    lsPanel = new lsPanelClass();
});

function ajaxQuestionVote(idTopic,idAnswer) {
	JsHttpRequest.query(
    	DIR_WEB_ROOT+'/include/ajax/questionVote.php',
        { idTopic: idTopic, idAnswer: idAnswer },
        function(result, errors) {
        	if (!result) {
                msgErrorBox.alert('Error','Please try again later');
        	}
            if (result.bStateError) {
            	msgErrorBox.alert(result.sMsgTitle,result.sMsg);
            } else {
            	msgNoticeBox.alert(result.sMsgTitle,result.sMsg);
            	if ($('topic_question_area_'+idTopic)) {
            		$('topic_question_area_'+idTopic).set('html',result.sText);
            	}
            }
        },
        true
    );
}

//MooTools More, <http://mootools.net/more>. Copyright (c) 2006-2008 Valerio Proietti, <http://mad4milk.net>, MIT Style License.

/*
Script: Fx.Slide.js
	Effect to slide an element in and out of view.

License:
	MIT-style license.
*/

Fx.Slide = new Class({

	Extends: Fx,

	options: {
		mode: 'vertical'
	},

	initialize: function(element, options){
		this.addEvent('complete', function(){
			this.open = (this.wrapper['offset' + this.layout.capitalize()] != 0);
			if (this.open && Browser.Engine.webkit419) this.element.dispose().inject(this.wrapper);
		}, true);
		this.element = this.subject = $(element);
		this.parent(options);
		var wrapper = this.element.retrieve('wrapper');
		this.wrapper = wrapper || new Element('div', {
			styles: $extend(this.element.getStyles('margin', 'position'), {'overflow': 'hidden'})
		}).wraps(this.element);
		this.element.store('wrapper', this.wrapper).setStyle('margin', 0);
		this.now = [];
		this.open = true;
	},

	vertical: function(){
		this.margin = 'margin-top';
		this.layout = 'height';
		this.offset = this.element.offsetHeight;
	},

	horizontal: function(){
		this.margin = 'margin-left';
		this.layout = 'width';
		this.offset = this.element.offsetWidth;
	},

	set: function(now){
		this.element.setStyle(this.margin, now[0]);
		this.wrapper.setStyle(this.layout, now[1]);
		return this;
	},

	compute: function(from, to, delta){
		var now = [];
		var x = 2;
		x.times(function(i){
			now[i] = Fx.compute(from[i], to[i], delta);
		});
		return now;
	},

	start: function(how, mode){
		if (!this.check(arguments.callee, how, mode)) return this;
		this[mode || this.options.mode]();
		var margin = this.element.getStyle(this.margin).toInt();
		var layout = this.wrapper.getStyle(this.layout).toInt();
		var caseIn = [[margin, layout], [0, this.offset]];
		var caseOut = [[margin, layout], [-this.offset, 0]];
		var start;
		switch (how){
			case 'in': start = caseIn; break;
			case 'out': start = caseOut; break;
			case 'toggle': start = (this.wrapper['offset' + this.layout.capitalize()] == 0) ? caseIn : caseOut;
		}
		return this.parent(start[0], start[1]);
	},

	slideIn: function(mode){
		return this.start('in', mode);
	},

	slideOut: function(mode){
		return this.start('out', mode);
	},

	hide: function(mode){
		this[mode || this.options.mode]();
		this.open = false;
		return this.set([-this.offset, 0]);
	},

	show: function(mode){
		this[mode || this.options.mode]();
		this.open = true;
		return this.set([0, this.offset]);
	},

	toggle: function(mode){
		return this.start('toggle', mode);
	}

});

Element.Properties.slide = {

	set: function(options){
		var slide = this.retrieve('slide');
		if (slide) slide.cancel();
		return this.eliminate('slide').store('slide:options', $extend({link: 'cancel'}, options));
	},

	get: function(options){
		if (options || !this.retrieve('slide')){
			if (options || !this.retrieve('slide:options')) this.set('slide', options);
			this.store('slide', new Fx.Slide(this, this.retrieve('slide:options')));
		}
		return this.retrieve('slide');
	}

};

Element.implement({

	slide: function(how, mode){
		how = how || 'toggle';
		var slide = this.get('slide'), toggle;
		switch (how){
			case 'hide': slide.hide(mode); break;
			case 'show': slide.show(mode); break;
			case 'toggle':
				var flag = this.retrieve('slide:flag', slide.open);
				slide[(flag) ? 'slideOut' : 'slideIn'](mode);
				this.store('slide:flag', !flag);
				toggle = true;
			break;
			default: slide.start(how, mode);
		}
		if (!toggle) this.eliminate('slide:flag');
		return this;
	}

});


/*
Script: Fx.Scroll.js
	Effect to smoothly scroll any element, including the window.

License:
	MIT-style license.
*/

Fx.Scroll = new Class({

	Extends: Fx,

	options: {
		offset: {'x': 0, 'y': 0},
		wheelStops: true
	},

	initialize: function(element, options){
		this.element = this.subject = $(element);
		this.parent(options);
		var cancel = this.cancel.bind(this, false);

		if ($type(this.element) != 'element') this.element = $(this.element.getDocument().body);

		var stopper = this.element;

		if (this.options.wheelStops){
			this.addEvent('start', function(){
				stopper.addEvent('mousewheel', cancel);
			}, true);
			this.addEvent('complete', function(){
				stopper.removeEvent('mousewheel', cancel);
			}, true);
		}
	},

	set: function(){
		var now = Array.flatten(arguments);
		this.element.scrollTo(now[0], now[1]);
	},

	compute: function(from, to, delta){
		var now = [];
		var x = 2;
		x.times(function(i){
			now.push(Fx.compute(from[i], to[i], delta));
		});
		return now;
	},

	start: function(x, y){
		if (!this.check(arguments.callee, x, y)) return this;
		var offsetSize = this.element.getSize(), scrollSize = this.element.getScrollSize();
		var scroll = this.element.getScroll(), values = {x: x, y: y};
		for (var z in values){
			var max = scrollSize[z] - offsetSize[z];
			if ($chk(values[z])) values[z] = ($type(values[z]) == 'number') ? values[z].limit(0, max) : max;
			else values[z] = scroll[z];
			values[z] += this.options.offset[z];
		}
		return this.parent([scroll.x, scroll.y], [values.x, values.y]);
	},

	toTop: function(){
		return this.start(false, 0);
	},

	toLeft: function(){
		return this.start(0, false);
	},

	toRight: function(){
		return this.start('right', false);
	},

	toBottom: function(){
		return this.start(false, 'bottom');
	},

	toElement: function(el){
		var position = $(el).getPosition(this.element);
		return this.start(position.x, position.y);
	}

});


/*
Script: Assets.js
	Provides methods to dynamically load JavaScript, CSS, and Image files into the document.

License:
	MIT-style license.
*/

var Asset = new Hash({

	javascript: function(source, properties){
		properties = $extend({
			onload: $empty,
			document: document,
			check: $lambda(true)
		}, properties);

		var script = new Element('script', {'src': source, 'type': 'text/javascript'});

		var load = properties.onload.bind(script), check = properties.check, doc = properties.document;
		delete properties.onload; delete properties.check; delete properties.document;

		script.addEvents({
			load: load,
			readystatechange: function(){
				if (['loaded', 'complete'].contains(this.readyState)) load();
			}
		}).setProperties(properties);


		if (Browser.Engine.webkit419) var checker = (function(){
			if (!$try(check)) return;
			$clear(checker);
			load();
		}).periodical(50);

		return script.inject(doc.head);
	},

	css: function(source, properties){
		return new Element('link', $merge({
			'rel': 'stylesheet', 'media': 'screen', 'type': 'text/css', 'href': source
		}, properties)).inject(document.head);
	},

	image: function(source, properties){
		properties = $merge({
			'onload': $empty,
			'onabort': $empty,
			'onerror': $empty
		}, properties);
		var image = new Image();
		var element = $(image) || new Element('img');
		['load', 'abort', 'error'].each(function(name){
			var type = 'on' + name;
			var event = properties[type];
			delete properties[type];
			image[type] = function(){
				if (!image) return;
				if (!element.parentNode){
					element.width = image.width;
					element.height = image.height;
				}
				image = image.onload = image.onabort = image.onerror = null;
				event.delay(1, element, element);
				element.fireEvent(name, element, 1);
			};
		});
		image.src = element.src = source;
		if (image && image.complete) image.onload.delay(1);
		return element.setProperties(properties);
	},

	images: function(sources, options){
		options = $merge({
			onComplete: $empty,
			onProgress: $empty
		}, options);
		if (!sources.push) sources = [sources];
		var images = [];
		var counter = 0;
		sources.each(function(source){
			var img = new Asset.image(source, {
				'onload': function(){
					options.onProgress.call(this, counter, sources.indexOf(source));
					counter++;
					if (counter == sources.length) options.onComplete();
				}
			});
			images.push(img);
		});
		return new Elements(images);
	}

});

/*
Script: Tips.js
	Class for creating nice tips that follow the mouse cursor when hovering an element.

License:
	MIT-style license.
*/

var Tips = new Class({

	Implements: [Events, Options],

	options: {
		onShow: function(tip){
			tip.setStyle('visibility', 'visible');
		},
		onHide: function(tip){
			tip.setStyle('visibility', 'hidden');
		},
		showDelay: 100,
		hideDelay: 100,
		className: null,
		offsets: {x: 16, y: 16},
		fixed: false
	},

	initialize: function(){
		var params = Array.link(arguments, {options: Object.type, elements: $defined});
		this.setOptions(params.options || null);

		this.tip = new Element('div').inject(document.body);

		if (this.options.className) this.tip.addClass(this.options.className);

		var top = new Element('div', {'class': 'tip-top'}).inject(this.tip);
		this.container = new Element('div', {'class': 'tip'}).inject(this.tip);
		var bottom = new Element('div', {'class': 'tip-bottom'}).inject(this.tip);

		this.tip.setStyles({position: 'absolute', top: 0, left: 0, visibility: 'hidden'});

		if (params.elements) this.attach(params.elements);
	},

	attach: function(elements){
		$$(elements).each(function(element){
			var title = element.retrieve('tip:title', element.get('title'));
			var text = element.retrieve('tip:text', element.get('rel') || element.get('href'));
			var enter = element.retrieve('tip:enter', this.elementEnter.bindWithEvent(this, element));
			var leave = element.retrieve('tip:leave', this.elementLeave.bindWithEvent(this, element));
			element.addEvents({mouseenter: enter, mouseleave: leave});
			if (!this.options.fixed){
				var move = element.retrieve('tip:move', this.elementMove.bindWithEvent(this, element));
				element.addEvent('mousemove', move);
			}
			element.store('tip:native', element.get('title'));
			element.erase('title');
		}, this);
		return this;
	},

	detach: function(elements){
		$$(elements).each(function(element){
			element.removeEvent('mouseenter', element.retrieve('tip:enter') || $empty);
			element.removeEvent('mouseleave', element.retrieve('tip:leave') || $empty);
			element.removeEvent('mousemove', element.retrieve('tip:move') || $empty);
			element.eliminate('tip:enter').eliminate('tip:leave').eliminate('tip:move');
			var original = element.retrieve('tip:native');
			if (original) element.set('title', original);
		});
		return this;
	},

	elementEnter: function(event, element){

		$A(this.container.childNodes).each(Element.dispose);

		var title = element.retrieve('tip:title');

		if (title){
			this.titleElement = new Element('div', {'class': 'tip-title'}).inject(this.container);
			this.fill(this.titleElement, title);
		}

		var text = element.retrieve('tip:text');
		if (text){
			this.textElement = new Element('div', {'class': 'tip-text'}).inject(this.container);
			this.fill(this.textElement, text);
		}

		this.timer = $clear(this.timer);
		this.timer = this.show.delay(this.options.showDelay, this);

		this.position((!this.options.fixed) ? event : {page: element.getPosition()});
	},

	elementLeave: function(event){
		$clear(this.timer);
		this.timer = this.hide.delay(this.options.hideDelay, this);
	},

	elementMove: function(event){
		this.position(event);
	},

	position: function(event){
		var size = window.getSize(), scroll = window.getScroll();
		var tip = {x: this.tip.offsetWidth, y: this.tip.offsetHeight};
		var props = {x: 'left', y: 'top'};
		for (var z in props){
			var pos = event.page[z] + this.options.offsets[z];
			if ((pos + tip[z] - scroll[z]) > size[z]) pos = event.page[z] - this.options.offsets[z] - tip[z];
			this.tip.setStyle(props[z], pos);
		}
	},

	fill: function(element, contents){
		(typeof contents == 'string') ? element.set('html', contents) : element.adopt(contents);
	},

	show: function(){
		this.fireEvent('show', this.tip);
	},

	hide: function(){
		this.fireEvent('hide', this.tip);
	}

});

/*
Script: SmoothScroll.js
	Class for creating a smooth scrolling effect to all internal links on the page.

License:
	MIT-style license.
*/

var SmoothScroll = new Class({

	Extends: Fx.Scroll,

	initialize: function(options, context){
		context = context || document;
		var doc = context.getDocument(), win = context.getWindow();
		this.parent(doc, options);
		this.links = (this.options.links) ? $$(this.options.links) : $$(doc.links);
		var location = win.location.href.match(/^[^#]*/)[0] + '#';
		this.links.each(function(link){
			if (link.href.indexOf(location) != 0) return;
			var anchor = link.href.substr(location.length);
			if (anchor && $(anchor)) this.useLink(link, anchor);
		}, this);
		if (!Browser.Engine.webkit419) this.addEvent('complete', function(){
			win.location.hash = this.anchor;
		}, true);
	},

	useLink: function(link, anchor){
		link.addEvent('click', function(event){
			this.anchor = anchor;
			this.toElement(anchor);
			event.stop();
		}.bind(this));
	}

});

/**
 * Observer - Observe formelements for changes
 *
 * - Additional code from clientside.cnet.com
 *
 * @version		1.1
 *
 * @license		MIT-style license
 * @author		Harald Kirschner <mail [at] digitarald.de>
 * @copyright	Author
 */
var Observer = new Class({

	Implements: [Options, Events],

	options: {
		periodical: false,
		delay: 1000
	},

	initialize: function(el, onFired, options){
		this.element = $(el) || $$(el);
		this.addEvent('onFired', onFired);
		this.setOptions(options);
		this.bound = this.changed.bind(this);
		this.resume();
	},

	changed: function() {
		var value = this.element.get('value');
		if ($equals(this.value, value)) return;
		this.clear();
		this.value = value;
		this.timeout = this.onFired.delay(this.options.delay, this);
	},

	setValue: function(value) {
		this.value = value;
		this.element.set('value', value);
		return this.clear();
	},

	onFired: function() {
		this.fireEvent('onFired', [this.value, this.element]);
	},

	clear: function() {
		$clear(this.timeout || null);
		return this;
	},

	pause: function(){
		if (this.timer) $clear(this.timer);
		else this.element.removeEvent('keyup', this.bound);
		return this.clear();
	},

	resume: function(){
		this.value = this.element.get('value');
		if (this.options.periodical) this.timer = this.changed.periodical(this.options.periodical, this);
		else this.element.addEvent('keyup', this.bound);
		return this;
	}

});

var $equals = function(obj1, obj2) {
	return (obj1 == obj2 || JSON.encode(obj1) == JSON.encode(obj2));
};

/**
 * Autocompleter
 *
 * http://digitarald.de/project/autocompleter/
 *
 * @version		1.1.2
 *
 * @license		MIT-style license
 * @author		Harald Kirschner <mail [at] digitarald.de>
 * @copyright	Author
 */

var Autocompleter = new Class({

	Implements: [Options, Events],

	options: {/*
		onOver: $empty,
		onSelect: $empty,
		onSelection: $empty,
		onShow: $empty,
		onHide: $empty,
		onBlur: $empty,
		onFocus: $empty,*/
		minLength: 1,
		markQuery: true,
		width: 'inherit',
		maxChoices: 10,
		injectChoice: null,
		customChoices: null,
		emptyChoices: null,
		visibleChoices: true,
		className: 'autocompleter-choices',
		zIndex: 42,
		delay: 400,
		observerOptions: {},
		fxOptions: {},

		autoSubmit: false,
		overflow: false,
		overflowMargin: 25,
		selectFirst: false,
		filter: null,
		filterCase: false,
		filterSubset: false,
		forceSelect: false,
		selectMode: true,
		choicesMatch: null,

		multiple: false,
		separator: ', ',
		separatorSplit: /\s*[,;]\s*/,
		autoTrim: false,
		allowDupes: false,

		cache: true,
		relative: false
	},

	initialize: function(element, options) {
		this.element = $(element);
		this.setOptions(options);
		this.build();
		this.observer = new Observer(this.element, this.prefetch.bind(this), $merge({
			'delay': this.options.delay
		}, this.options.observerOptions));
		this.queryValue = null;
		if (this.options.filter) this.filter = this.options.filter.bind(this);
		var mode = this.options.selectMode;
		this.typeAhead = (mode == 'type-ahead');
		this.selectMode = (mode === true) ? 'selection' : mode;
		this.cached = [];
	},

	/**
	 * build - Initialize DOM
	 *
	 * Builds the html structure for choices and appends the events to the element.
	 * Override this function to modify the html generation.
	 */
	build: function() {
		if ($(this.options.customChoices)) {
			this.choices = this.options.customChoices;
		} else {
			this.choices = new Element('ul', {
				'class': this.options.className,
				'styles': {
					'zIndex': this.options.zIndex
				}
			}).inject(document.body);
			this.relative = false;
			if (this.options.relative) {
				this.choices.inject(this.element, 'after');
				this.relative = this.element.getOffsetParent();
			}
			this.fix = new OverlayFix(this.choices);
		}
		if (!this.options.separator.test(this.options.separatorSplit)) {
			this.options.separatorSplit = this.options.separator;
		}
		this.fx = (!this.options.fxOptions) ? null : new Fx.Tween(this.choices, $merge({
			'property': 'opacity',
			'link': 'cancel',
			'duration': 200
		}, this.options.fxOptions)).addEvent('onStart', Chain.prototype.clearChain).set(0);
		this.element.setProperty('autocomplete', 'off')
			.addEvent((Browser.Engine.trident || Browser.Engine.webkit) ? 'keydown' : 'keypress', this.onCommand.bind(this))
			.addEvent('click', this.onCommand.bind(this, [false]))
			.addEvent('focus', this.toggleFocus.create({bind: this, arguments: true, delay: 100}))
			.addEvent('blur', this.toggleFocus.create({bind: this, arguments: false, delay: 100}));
	},

	destroy: function() {
		if (this.fix) this.fix.destroy();
		this.choices = this.selected = this.choices.destroy();
	},

	toggleFocus: function(state) {
		this.focussed = state;
		if (!state) this.hideChoices(true);
		this.fireEvent((state) ? 'onFocus' : 'onBlur', [this.element]);
	},

	onCommand: function(e) {
		if (!e && this.focussed) return this.prefetch();
		if (e && e.key && !e.shift) {
			switch (e.key) {
				case 'enter':
					if (this.element.value != this.opted) return true;
					if (this.selected && this.visible) {
						this.choiceSelect(this.selected);
						return !!(this.options.autoSubmit);
					}
					break;
				case 'up': case 'down':
					if (!this.prefetch() && this.queryValue !== null) {
						var up = (e.key == 'up');
						this.choiceOver((this.selected || this.choices)[
							(this.selected) ? ((up) ? 'getPrevious' : 'getNext') : ((up) ? 'getLast' : 'getFirst')
						](this.options.choicesMatch), true);
					}
					return false;
				case 'esc': case 'tab':
					this.hideChoices(true);
					break;
			}
		}
		return true;
	},

	setSelection: function(finish) {
		var input = this.selected.inputValue, value = input;
		var start = this.queryValue.length, end = input.length;
		if (input.substr(0, start).toLowerCase() != this.queryValue.toLowerCase()) start = 0;
		if (this.options.multiple) {
			var split = this.options.separatorSplit;
			value = this.element.value;
			start += this.queryIndex;
			end += this.queryIndex;
			var old = value.substr(this.queryIndex).split(split, 1)[0];
			value = value.substr(0, this.queryIndex) + input + value.substr(this.queryIndex + old.length);
			if (finish) {
				var tokens = value.split(this.options.separatorSplit).filter(function(entry) {
					return this.test(entry);
				}, /[^\s,]+/);
				if (!this.options.allowDupes) tokens = [].combine(tokens);
				var sep = this.options.separator;
				value = tokens.join(sep) + sep;
				end = value.length;
			}
		}
		this.observer.setValue(value);
		this.opted = value;
		if (finish || this.selectMode == 'pick') start = end;
		this.element.selectRange(start, end);
		this.fireEvent('onSelection', [this.element, this.selected, value, input]);
	},

	showChoices: function() {
		var match = this.options.choicesMatch, first = this.choices.getFirst(match);
		this.selected = this.selectedValue = null;
		if (this.fix) {
			var pos = this.element.getCoordinates(this.relative), width = this.options.width || 'auto';
			this.choices.setStyles({
				'left': pos.left,
				'top': pos.bottom,
				'width': (width === true || width == 'inherit') ? pos.width : width
			});
		}
		if (!first) return;
		if (!this.visible) {
			this.visible = true;
			this.choices.setStyle('display', '');
			if (this.fx) this.fx.start(1);
			this.fireEvent('onShow', [this.element, this.choices]);
		}
		if (this.options.selectFirst || this.typeAhead || first.inputValue == this.queryValue) this.choiceOver(first, this.typeAhead);
		var items = this.choices.getChildren(match), max = this.options.maxChoices;
		var styles = {'overflowY': 'hidden', 'height': ''};
		this.overflown = false;
		if (items.length > max) {
			var item = items[max - 1];
			styles.overflowY = 'scroll';
			styles.height = item.getCoordinates(this.choices).bottom;
			this.overflown = true;
		};
		this.choices.setStyles(styles);
		this.fix.show();
		if (this.options.visibleChoices) {
			var scroll = document.getScroll(),
			size = document.getSize(),
			coords = this.choices.getCoordinates();
			if (coords.right > scroll.x + size.x) scroll.x = coords.right - size.x;
			if (coords.bottom > scroll.y + size.y) scroll.y = coords.bottom - size.y;
			window.scrollTo(Math.min(scroll.x, coords.left), Math.min(scroll.y, coords.top));
		}
	},

	hideChoices: function(clear) {
		if (clear) {
			var value = this.element.value;
			if (this.options.forceSelect) value = this.opted;
			if (this.options.autoTrim) {
				value = value.split(this.options.separatorSplit).filter($arguments(0)).join(this.options.separator);
			}
			this.observer.setValue(value);
		}
		if (!this.visible) return;
		this.visible = false;
		if (this.selected) this.selected.removeClass('autocompleter-selected');
		this.observer.clear();
		var hide = function(){
			this.choices.setStyle('display', 'none');
			this.fix.hide();
		}.bind(this);
		if (this.fx) this.fx.start(0).chain(hide);
		else hide();
		this.fireEvent('onHide', [this.element, this.choices]);
	},

	prefetch: function() {
		var value = this.element.value, query = value;
		if (this.options.multiple) {
			var split = this.options.separatorSplit;
			var values = value.split(split);
			var index = this.element.getSelectedRange().start;
			var toIndex = value.substr(0, index).split(split);
			var last = toIndex.length - 1;
			index -= toIndex[last].length;
			query = values[last];
		}
		if (query.length < this.options.minLength) {
			this.hideChoices();
		} else {
			if (query === this.queryValue || (this.visible && query == this.selectedValue)) {
				if (this.visible) return false;
				this.showChoices();
			} else {
				this.queryValue = query;
				this.queryIndex = index;
				if (!this.fetchCached()) this.query();
			}
		}
		return true;
	},

	fetchCached: function() {
		return false;
		if (!this.options.cache
			|| !this.cached
			|| !this.cached.length
			|| this.cached.length >= this.options.maxChoices
			|| this.queryValue) return false;
		this.update(this.filter(this.cached));
		return true;
	},

	update: function(tokens) {
		this.choices.empty();
		this.cached = tokens;
		var type = tokens && $type(tokens);
		if (!type || (type == 'array' && !tokens.length) || (type == 'hash' && !tokens.getLength())) {
			(this.options.emptyChoices || this.hideChoices).call(this);
		} else {
			if (this.options.maxChoices < tokens.length && !this.options.overflow) tokens.length = this.options.maxChoices;
			tokens.each(this.options.injectChoice || function(token){
				var choice = new Element('li', {'html': this.markQueryValue(token)});
				choice.inputValue = token;
				this.addChoiceEvents(choice).inject(this.choices);
			}, this);
			this.showChoices();
		}
	},

	choiceOver: function(choice, selection) {
		if (!choice || choice == this.selected) return;
		if (this.selected) this.selected.removeClass('autocompleter-selected');
		this.selected = choice.addClass('autocompleter-selected');
		this.fireEvent('onSelect', [this.element, this.selected, selection]);
		if (!this.selectMode) this.opted = this.element.value;
		if (!selection) return;
		this.selectedValue = this.selected.inputValue;
		if (this.overflown) {
			var coords = this.selected.getCoordinates(this.choices), margin = this.options.overflowMargin,
				top = this.choices.scrollTop, height = this.choices.offsetHeight, bottom = top + height;
			if (coords.top - margin < top && top) this.choices.scrollTop = Math.max(coords.top - margin, 0);
			else if (coords.bottom + margin > bottom) this.choices.scrollTop = Math.min(coords.bottom - height + margin, bottom);
		}
		if (this.selectMode) this.setSelection();
	},

	choiceSelect: function(choice) {
		if (choice) this.choiceOver(choice);
		this.setSelection(true);
		this.queryValue = false;
		this.hideChoices();
	},

	filter: function(tokens) {
		return (tokens || this.tokens).filter(function(token) {
			return this.test(token);
		}, new RegExp(((this.options.filterSubset) ? '' : '^') + this.queryValue.escapeRegExp(), (this.options.filterCase) ? '' : 'i'));
	},

	/**
	 * markQueryValue
	 *
	 * Marks the queried word in the given string with <span class="autocompleter-queried">*</span>
	 * Call this i.e. from your custom parseChoices, same for addChoiceEvents
	 *
	 * @param		{String} Text
	 * @return		{String} Text
	 */
	markQueryValue: function(str) {
		return (!this.options.markQuery || !this.queryValue) ? str
			: str.replace(new RegExp('(' + ((this.options.filterSubset) ? '' : '^') + this.queryValue.escapeRegExp() + ')', (this.options.filterCase) ? '' : 'i'), '<span class="autocompleter-queried">$1</span>');
	},

	/**
	 * addChoiceEvents
	 *
	 * Appends the needed event handlers for a choice-entry to the given element.
	 *
	 * @param		{Element} Choice entry
	 * @return		{Element} Choice entry
	 */
	addChoiceEvents: function(el) {
		return el.addEvents({
			'mouseover': this.choiceOver.bind(this, [el]),
			'click': this.choiceSelect.bind(this, [el])
		});
	}
});

var OverlayFix = new Class({

	initialize: function(el) {
		if (Browser.Engine.trident) {
			this.element = $(el);
			this.relative = this.element.getOffsetParent();
			this.fix = new Element('iframe', {
				'frameborder': '0',
				'scrolling': 'no',
				'src': 'javascript:false;',
				'styles': {
					'position': 'absolute',
					'border': 'none',
					'display': 'none',
					'filter': 'progid:DXImageTransform.Microsoft.Alpha(opacity=0)'
				}
			}).inject(this.element, 'after');
		}
	},

	show: function() {
		if (this.fix) {
			var coords = this.element.getCoordinates(this.relative);
			delete coords.right;
			delete coords.bottom;
			this.fix.setStyles($extend(coords, {
				'display': '',
				'zIndex': (this.element.getStyle('zIndex') || 1) - 1
			}));
		}
		return this;
	},

	hide: function() {
		if (this.fix) this.fix.setStyle('display', 'none');
		return this;
	},

	destroy: function() {
		if (this.fix) this.fix = this.fix.destroy();
	}

});

Element.implement({

	getSelectedRange: function() {
		if (!Browser.Engine.trident) return {start: this.selectionStart, end: this.selectionEnd};
		var pos = {start: 0, end: 0};
		var range = this.getDocument().selection.createRange();
		if (!range || range.parentElement() != this) return pos;
		var dup = range.duplicate();
		if (this.type == 'text') {
			pos.start = 0 - dup.moveStart('character', -100000);
			pos.end = pos.start + range.text.length;
		} else {
			var value = this.value;
			var offset = value.length - value.match(/[\n\r]*$/)[0].length;
			dup.moveToElementText(this);
			dup.setEndPoint('StartToEnd', range);
			pos.end = offset - dup.text.length;
			dup.setEndPoint('StartToStart', range);
			pos.start = offset - dup.text.length;
		}
		return pos;
	},

	selectRange: function(start, end) {
		if (Browser.Engine.trident) {
			var diff = this.value.substr(start, end - start).replace(/\r/g, '').length;
			start = this.value.substr(0, start).replace(/\r/g, '').length;
			var range = this.createTextRange();
			range.collapse(true);
			range.moveEnd('character', start + diff);
			range.moveStart('character', start);
			range.select();
		} else {
			this.focus();
			this.setSelectionRange(start, end);
		}
		return this;
	}

});

/* compatibility */

Autocompleter.Base = Autocompleter;

/**
 * Autocompleter.Request
 *
 * http://digitarald.de/project/autocompleter/
 *
 * @version		1.1.2
 *
 * @license		MIT-style license
 * @author		Harald Kirschner <mail [at] digitarald.de>
 * @copyright	Author
 */

Autocompleter.Request = new Class({

	Extends: Autocompleter,

	options: {/*
		indicator: null,
		indicatorClass: null,
		onRequest: $empty,
		onComplete: $empty,*/
		postData: {},
		ajaxOptions: {},
		postVar: 'value'

	},

	query: function(){
		var data = $unlink(this.options.postData) || {};
		data[this.options.postVar] = this.queryValue;
		var indicator = $(this.options.indicator);
		if (indicator) indicator.setStyle('display', '');
		var cls = this.options.indicatorClass;
		if (cls) this.element.addClass(cls);
		this.fireEvent('onRequest', [this.element, this.request, data, this.queryValue]);
		this.request.send({'data': data});
	},

	/**
	 * queryResponse - abstract
	 *
	 * Inherated classes have to extend this function and use this.parent()
	 */
	queryResponse: function() {
		var indicator = $(this.options.indicator);
		if (indicator) indicator.setStyle('display', 'none');
		var cls = this.options.indicatorClass;
		if (cls) this.element.removeClass(cls);
		return this.fireEvent('onComplete', [this.element, this.request]);
	}

});

Autocompleter.Request.JSON = new Class({

	Extends: Autocompleter.Request,

	initialize: function(el, url, options) {
		this.parent(el, options);
		this.request = new Request.JSON($merge({
			'url': url,
			'link': 'cancel'
		}, this.options.ajaxOptions)).addEvent('onComplete', this.queryResponse.bind(this));
	},

	queryResponse: function(response) {
		this.parent();
		this.update(response);
	}

});

Autocompleter.Request.HTML = new Class({

	Extends: Autocompleter.Request,

	initialize: function(el, url, options) {
		this.parent(el, options);
		this.request = new Request.HTML($merge({
			'url': url,
			'link': 'cancel',
			'update': this.choices
		}, this.options.ajaxOptions)).addEvent('onComplete', this.queryResponse.bind(this));
	},

	queryResponse: function(tree, elements) {
		this.parent();
		if (!elements || !elements.length) {
			this.hideChoices();
		} else {
			this.choices.getChildren(this.options.choicesMatch).each(this.options.injectChoice || function(choice) {
				var value = choice.get('text');
				choice.inputValue = value;
				this.addChoiceEvents(choice.set('html', this.markQueryValue(value)));
			}, this);
			this.showChoices();
		}

	}

});

/* compatibility */

Autocompleter.Ajax = {
	Base: Autocompleter.Request,
	Json: Autocompleter.Request.JSON,
	Xhtml: Autocompleter.Request.HTML
};

/*
Script: Element.Forms.js
	Extends the Element native object to include methods useful in managing inputs.

License:
	http://www.clientcide.com/wiki/cnet-libraries#license
*/
Element.implement({
	tidy: function(){
		this.set('value', this.get('value').tidy());
	},
	getTextInRange: function(start, end) {
		return this.get('value').substring(start, end);
	},
	getSelectedText: function() {
		if(Browser.Engine.trident) return document.selection.createRange().text;
		return this.get('value').substring(this.getSelectionStart(), this.getSelectionEnd());
	},
	getIERanges: function(){
		this.focus();
		var range = document.selection.createRange();
		var re = this.createTextRange();
		var dupe = re.duplicate();
		re.moveToBookmark(range.getBookmark());
		dupe.setEndPoint('EndToStart', re);
		return { start: dupe.text.length, end: dupe.text.length + range.text.length, length: range.text.length, text: range.text };
	},
	getSelectionStart: function() {
		if(Browser.Engine.trident) return this.getIERanges().start;
		return this.selectionStart;
	},
	getSelectionEnd: function() {
		if(Browser.Engine.trident) return this.getIERanges().end;
		return this.selectionEnd;
	},
	getSelectedRange: function() {
		return {
			start: this.getSelectionStart(),
			end: this.getSelectionEnd()
		}
	},
	setCaretPosition: function(pos) {
		if(pos == 'end') pos = this.get('value').length;
		this.selectRange(pos, pos);
		return this;
	},
	getCaretPosition: function() {
		return this.getSelectedRange().start;
	},
	selectRange: function(start, end) {
		this.focus();
		if(Browser.Engine.trident) {
			var range = this.createTextRange();
			range.collapse(true);
			range.moveStart('character', start);
			range.moveEnd('character', end - start);
			range.select();
			return this;
		}
		this.setSelectionRange(start, end);
		return this;
	},
	insertAtCursor: function(value, select) {
		var start = this.getSelectionStart();
		var end = this.getSelectionEnd();
		this.set('value', this.get('value').substring(0, start) + value + this.get('value').substring(end, this.get('value').length));
 		if($pick(select, true)) this.selectRange(start, start + value.length);
		else this.setCaretPosition(start + value.length);
		return this;
	},
	insertAroundCursor: function(options, select) {
		options = $extend({
			before: '',
			defaultMiddle: 'SOMETHING HERE',
			after: ''
		}, options);
		value = this.getSelectedText() || options.defaultMiddle;
		var start = this.getSelectionStart();
		var end = this.getSelectionEnd();
		if(start == end) {
			var text = this.get('value');
			this.set('value', text.substring(0, start) + options.before + value + options.after + text.substring(end, text.length));
			this.selectRange(start + options.before.length, end + options.before.length + value.length);
			text = null;
		} else {
			text = this.get('value').substring(start, end);
			this.set('value', this.get('value').substring(0, start) + options.before + text + options.after + this.get('value').substring(end, this.get('value').length));
			var selStart = start + options.before.length;
			if($pick(select, true)) this.selectRange(selStart, selStart + text.length);
			else this.setCaretPosition(selStart + text.length);
		}
		return this;
	}
});


Element.Properties.inputValue = {

    get: function(){
			 switch(this.get('tag')) {
			 	case 'select':
					vals = this.getSelected().map(function(op){
						var v = $pick(op.get('value'),op.get('text'));
						return (v=="")?op.get('text'):v;
					});
					return this.get('multiple')?vals:vals[0];
				case 'input':
					switch(this.get('type')) {
						case 'checkbox':
							return this.get('checked')?this.get('value'):false;
						case 'radio':
							var checked;
							if (this.get('checked')) return this.get('value');
							$(this.getParent('form')||document.body).getElements('input').each(function(input){
								if (input.get('name') == this.get('name') && input.get('checked')) checked = input.get('value');
							}, this);
							return checked||null;
					}
			 	case 'input': case 'textarea':
					return this.get('value');
				default:
					return this.get('inputValue');
			 }
    },

    set: function(value){
			switch(this.get('tag')){
				case 'select':
					this.getElements('option').each(function(op){
						var v = $pick(op.get('value'), op.get('text'));
						if (v=="") v = op.get('text');
						op.set('selected', $splat(value).contains(v));
					});
					break;
				case 'input':
					if (['radio','checkbox'].contains(this.get('type'))) {
						this.set('checked', $type(value)=="boolean"?value:$splat(value).contains(this.get('value')));
						break;
					}
				case 'textarea': case 'input':
					this.set('value', value);
					break;
				default:
					this.set('inputValue', value);
			}
			return this;
    },

	erase: function() {
		switch(this.get('tag')) {
			case 'select':
				this.getElements('option').each(function(op) {
					op.erase('selected');
				});
				break;
			case 'input':
				if (['radio','checkbox'].contains(this.get('type'))) {
					this.set('checked', false);
					break;
				}
			case 'input': case 'textarea':
				this.set('value', '');
				break;
			default:
				this.set('inputValue', '');
		}
		return this;
	}

};

/*
Script: Clientcide.js
	The Clientcide namespace.

License:
	http://www.clientcide.com/wiki/cnet-libraries#license
*/


/*
Script: dbug.js
	A wrapper for Firebug console.* statements.

License:
	http://www.clientcide.com/wiki/cnet-libraries#license
*/
var dbug = {
	logged: [],
	timers: {},
	firebug: false,
	enabled: false,
	log: function() {
		dbug.logged.push(arguments);
	},
	nolog: function(msg) {
		dbug.logged.push(arguments);
	},
	time: function(name){
		dbug.timers[name] = new Date().getTime();
	},
	timeEnd: function(name){
		if (dbug.timers[name]) {
			var end = new Date().getTime() - dbug.timers[name];
			dbug.timers[name] = false;
			dbug.log('%s: %s', name, end);
		} else dbug.log('no such timer: %s', name);
	},
	enable: function(silent) {
		if(dbug.firebug) {
			try {
				dbug.enabled = true;
				dbug.log = function(){
						(console.debug || console.log).apply(console, arguments);
				};
				dbug.time = function(){
					console.time.apply(console, arguments);
				};
				dbug.timeEnd = function(){
					console.timeEnd.apply(console, arguments);
				};
				if(!silent) dbug.log('enabling dbug');
				for(var i=0;i<dbug.logged.length;i++){ dbug.log.apply(console, dbug.logged[i]); }
				dbug.logged=[];
			} catch(e) {
				dbug.enable.delay(400);
			}
		}
	},
	disable: function(){
		if(dbug.firebug) dbug.enabled = false;
		dbug.log = dbug.nolog;
		dbug.time = function(){};
		dbug.timeEnd = function(){};
	},
	cookie: function(set){
		var value = document.cookie.match('(?:^|;)\\s*jsdebug=([^;]*)');
		var debugCookie = value ? unescape(value[1]) : false;
		if((!$defined(set) && debugCookie != 'true') || ($defined(set) && set)) {
			dbug.enable();
			dbug.log('setting debugging cookie');
			var date = new Date();
			date.setTime(date.getTime()+(24*60*60*1000));
			document.cookie = 'jsdebug=true;expires='+date.toGMTString()+';path=/;';
		} else dbug.disableCookie();
	},
	disableCookie: function(){
		dbug.log('disabling debugging cookie');
		document.cookie = 'jsdebug=false;path=/;';
	}
};

(function(){
	var fb = typeof console != "undefined";
	var debugMethods = ['debug','info','warn','error','assert','dir','dirxml'];
	var otherMethods = ['trace','group','groupEnd','profile','profileEnd','count'];
	function set(methodList, defaultFunction) {
		for(var i = 0; i < methodList.length; i++){
			dbug[methodList[i]] = (fb && console[methodList[i]])?console[methodList[i]]:defaultFunction;
		}
	};
	set(debugMethods, dbug.log);
	set(otherMethods, function(){});
})();
if (typeof console != "undefined" && console.warn){
	dbug.firebug = true;
	var value = document.cookie.match('(?:^|;)\\s*jsdebug=([^;]*)');
	var debugCookie = value ? unescape(value[1]) : false;
	if(window.location.href.indexOf("jsdebug=true")>0 || debugCookie=='true') dbug.enable();
	if(debugCookie=='true')dbug.log('debugging cookie enabled');
	if(window.location.href.indexOf("jsdebugCookie=true")>0){
		dbug.cookie();
		if(!dbug.enabled)dbug.enable();
	}
	if(window.location.href.indexOf("jsdebugCookie=false")>0)dbug.disableCookie();
}


/*
Script: Occlude.js
	Prevents a class from being applied to a DOM element twice.

License:
	http://www.clientcide.com/wiki/cnet-libraries#license
*/
var Occlude = new Class({
	// usage: if(this.occlude()) return this.occluded;
	occlude: function(property, element) {
		element = $(element || this.element);
		var instance = element.retrieve(property || this.property);
		if (instance && (this.occluded === null || this.occluded)) {
			this.occluded = instance;
		} else {
			this.occluded = false;
			element.store(property || this.property, this);
		}
		return this.occluded||false;
	}
});

/*
Script: ToElement.js
	Defines the toElement method for a class.

License:
	http://www.clientcide.com/wiki/cnet-libraries#license
*/
var ToElement = new Class({
	toElement: function(){
		return this.element;
	}
});

/*
Script: IframeShim.js
	Defines IframeShim, a class for obscuring select lists and flash objects in IE.

License:
	http://www.clientcide.com/wiki/cnet-libraries#license
*/
var IframeShim = new Class({
	Implements: [Options, Events, Occlude, ToElement],
	options: {
		className:'iframeShim',
		display:false,
		zindex: null,
		margin: 0,
		offset: {
			x: 0,
			y: 0
		},
		browsers: (Browser.Engine.trident4 || (Browser.Engine.gecko && !Browser.Engine.gecko19 && Browser.Platform.mac))
	},
	property: 'IframeShim',
	initialize: function (element, options){
		this.element = $(element);
		if (this.occlude()) return this.occluded;
		this.setOptions(options);
		this.makeShim();
		return;
	},
	makeShim: function(){
		this.shim = new Element('iframe').store('IframeShim', this);
		if(!this.options.browsers) return;
		if(this.element.getStyle('z-Index').toInt()<1 || isNaN(this.element.getStyle('z-Index').toInt()))
			this.element.setStyle('z-Index',5);
		var z = this.element.getStyle('z-Index')-1;

		if($chk(this.options.zindex) &&
			 this.element.getStyle('z-Index').toInt() > this.options.zindex)
			 z = this.options.zindex;

 		this.shim.set({
			src: (window.location.protocol == 'https') ? '://0' : 'javascript:void(0)',
			frameborder:'0',
			scrolling:'no',
			styles: {
				position: 'absolute',
				zIndex: z,
				border: 'none',
				filter: 'progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)'
			},
			'class':this.options.className
		});

		var inject = function(){
			this.shim.inject(this.element, 'after');
			if(this.options.display) this.show();
			else this.hide();
			this.fireEvent('onInject');
		};
		if(Browser.Engine.trident && !IframeShim.ready) window.addEvent('load', inject.bind(this));
		else inject.run(null, this);
	},
	position: function(shim){
		if(!this.options.browsers || !IframeShim.ready) return this;
		var size = this.element.measure(function(){ return this.getSize(); });
		if($type(this.options.margin)){
			size.x = size.x-(this.options.margin*2);
			size.y = size.y-(this.options.margin*2);
			this.options.offset.x += this.options.margin;
			this.options.offset.y += this.options.margin;
		}
 		this.shim.set({
			'width': size.x,
			'height': size.y
		}).setPosition({
			relativeTo: this.element,
			offset: this.options.offset
		});
		return this;
	},
	hide: function(){
		if(this.options.browsers) this.shim.hide();
		return this;
	},
	show: function(){
		if(!this.options.browsers) return this;
		this.shim.show();
		return this.position();
	},
	dispose: function(){
		if(this.options.browsers) this.shim.dispose();
		return this;
	}
});
window.addEvent('load', function(){
	IframeShim.ready = true;
});


/*
Script: Element.Measure.js
	Extends the Element native object to include methods useful in measuring dimensions.

License:
	http://www.clientcide.com/wiki/cnet-libraries#license
*/

Element.implement({

	// Daniel Steigerwald - MIT licence
	measure: function(fn) {
		var restore = this.expose();
		var result = fn.apply(this);
		restore();
		return result;
	},

	expose: function(){
		var style = this.style;
    var cssText = style.cssText;
    style.visibility = 'hidden';
    style.position = 'absolute';
    if (style.display == 'none') style.display = '';
		return (function(){ return this.set('style', cssText); }).bind(this);
	},

	getDimensions: function(options) {
		options = $merge({computeSize: false},options);
		var dim = {};
		function getSize(el, options){
			return (options.computeSize)?el.getComputedSize(options):el.getSize();
		};
		if(this.getStyle('display') == 'none'){
			var restore = this.expose();
			dim = getSize(this, options); //works now, because the display isn't none
			restore(); //put it back where it was
		} else {
			try { //safari sometimes crashes here, so catch it
				dim = getSize(this, options);
			}catch(e){}
		}
		return $chk(dim.x)?$extend(dim, {width: dim.x, height: dim.y}):$extend(dim, {x: dim.width, y: dim.height});
	},

	getComputedSize: function(options){
		options = $merge({
			styles: ['padding','border'],
			plains: {height: ['top','bottom'], width: ['left','right']},
			mode: 'both'
		}, options);
		var size = {width: 0,height: 0};
		switch (options.mode){
			case 'vertical':
				delete size.width;
				delete options.plains.width;
				break;
			case 'horizontal':
				delete size.height;
				delete options.plains.height;
				break;
		};
		var getStyles = [];
		//this function might be useful in other places; perhaps it should be outside this function?
		$each(options.plains, function(plain, key){
			plain.each(function(edge){
				options.styles.each(function(style){
					getStyles.push((style=="border")?style+'-'+edge+'-'+'width':style+'-'+edge);
				});
			});
		});
		var styles = this.getStyles.apply(this, getStyles);
		var subtracted = [];
		$each(options.plains, function(plain, key){ //keys: width, height, plains: ['left','right'], ['top','bottom']
			size['total'+key.capitalize()] = 0;
			size['computed'+key.capitalize()] = 0;
			plain.each(function(edge){ //top, left, right, bottom
				size['computed'+edge.capitalize()] = 0;
				getStyles.each(function(style,i){ //padding, border, etc.
					//'padding-left'.test('left') size['totalWidth'] = size['width']+[padding-left]
					if(style.test(edge)) {
						styles[style] = styles[style].toInt(); //styles['padding-left'] = 5;
						if(isNaN(styles[style]))styles[style]=0;
						size['total'+key.capitalize()] = size['total'+key.capitalize()]+styles[style];
						size['computed'+edge.capitalize()] = size['computed'+edge.capitalize()]+styles[style];
					}
					//if width != width (so, padding-left, for instance), then subtract that from the total
					if(style.test(edge) && key!=style &&
						(style.test('border') || style.test('padding')) && !subtracted.contains(style)) {
						subtracted.push(style);
						size['computed'+key.capitalize()] = size['computed'+key.capitalize()]-styles[style];
					}
				});
			});
		});
		if($chk(size.width)) {
			size.width = size.width+this.offsetWidth+size.computedWidth;
			size.totalWidth = size.width + size.totalWidth;
			delete size.computedWidth;
		}
		if($chk(size.height)) {
			size.height = size.height+this.offsetHeight+size.computedHeight;
			size.totalHeight = size.height + size.totalHeight;
			delete size.computedHeight;
		}
		return $extend(styles, size);
	}
});


/*
Script: Element.Pin.js
	Extends the Element native object to include the pin method useful for fixed positioning for elements.

License:
	http://www.clientcide.com/wiki/cnet-libraries#license
*/

window.addEvent('domready', function(){
	var test = new Element('div').setStyles({
		position: 'fixed',
		top: 0,
		right: 0
	}).inject(document.body);
	var supported = (test.offsetTop === 0);
	test.dispose();
	Browser.supportsPositionFixed = supported;
});

Element.implement({
	pin: function(enable){
		if(!Browser.loaded) dbug.log('cannot pin ' + this + ' natively because the dom is not ready');
		if (this.getStyle('display') == 'none') {
			dbug.log('cannot pin ' + this + ' because it is hidden');
			return;
		}
		if(enable!==false) {
			var p = this.getPosition();
			if(!this.retrieve('pinned')) {
				var pos = {
					top: (p.y - window.getScroll().y),
					left: (p.x - window.getScroll().x)
				};
				if(Browser.supportsPositionFixed) {
					this.setStyle('position','fixed').setStyles(pos);
				} else {
					this.store('pinnedByJS', true);
					this.setStyles({
						position: 'absolute',
						top: p.y,
						left: p.x
					});
					this.store('scrollFixer', function(){
						if(this.retrieve('pinned')) {
							var to = {
								top: (pos.top.toInt() + window.getScroll().y),
								left: (pos.left.toInt() + window.getScroll().x)
							};
							this.setStyles(to);
						}
					}.bind(this));
					window.addEvent('scroll', this.retrieve('scrollFixer'));
				}
				this.store('pinned', true);
			}
		} else {
			var op;
			if (!Browser.Engine.trident) {
				if (this.getParent().getComputedStyle('position') != 'static') op = this.getParent();
				else op = this.getParent().getOffsetParent();
			}
			var p = this.getPosition(op);
			this.store('pinned', false);
			var reposition;
			if (Browser.supportsPositionFixed && !this.retrieve('pinnedByJS')) {
				reposition = {
					top: (p.y + window.getScroll().y),
					left: (p.x + window.getScroll().x)
				};
			} else {
				this.store('pinnedByJS', false);
				window.removeEvent('scroll', this.retrieve('scrollFixer'));
				reposition = {
					top: (p.y),
					left: (p.x)
				};
			}
			this.setStyles($merge(reposition, {position: 'absolute'}));
		}
		return this.addClass('isPinned');
	},
	unpin: function(){
		return this.pin(false).removeClass('isPinned');
	},
	togglepin: function(){
		this.pin(!this.retrieve('pinned'));
	}
});


/*
Script: Element.Position.js
	Extends the Element native object to include methods useful positioning elements relative to others.

License:
	http://www.clientcide.com/wiki/cnet-libraries#license
*/

Element.Properties.position = {

	set: function(options){
		this.setPosition(options);
	},

	get: function(options){
		if (options) this.setPosition(options);
		return this.getPosition();
	}

};

Element.implement({

	setPosition: function(options){
		$each(options||{}, function(v, k){ if (!$defined(v)) delete options[k]; });
		options = $merge({
			relativeTo: document.body,
			position: {
				x: 'center', //left, center, right
				y: 'center' //top, center, bottom
			},
			edge: false,
			offset: {x: 0, y: 0},
			returnPos: false,
			relFixedPosition: false,
			ignoreMargins: false,
			allowNegative: false
		}, options);
		//compute the offset of the parent positioned element if this element is in one
		var parentOffset = {x: 0, y: 0};
		var parentPositioned = false;
		/* dollar around getOffsetParent should not be necessary, but as it does not return
		 * a mootools extended element in IE, an error occurs on the call to expose. See:
		 * http://mootools.lighthouseapp.com/projects/2706/tickets/333-element-getoffsetparent-inconsistency-between-ie-and-other-browsers */
		var offsetParent = this.measure(function(){
			return $(this.getOffsetParent());
		});
		if (offsetParent && offsetParent != this.getDocument().body){
			parentOffset = offsetParent.measure(function(){
				return this.getPosition();
			});
			parentPositioned = true;
			options.offset.x = options.offset.x - parentOffset.x;
			options.offset.y = options.offset.y - parentOffset.y;
		}
		//upperRight, bottomRight, centerRight, upperLeft, bottomLeft, centerLeft
		//topRight, topLeft, centerTop, centerBottom, center
		var fixValue = function(option){
			if ($type(option) != "string") return option;
			option = option.toLowerCase();
			var val = {};
			if (option.test('left')) val.x = 'left';
			else if (option.test('right')) val.x = 'right';
			else val.x = 'center';
			if (option.test('upper') || option.test('top')) val.y = 'top';
			else if (option.test('bottom')) val.y = 'bottom';
			else val.y = 'center';
			return val;
		};
		options.edge = fixValue(options.edge);
		options.position = fixValue(options.position);
		if (!options.edge){
			if (options.position.x == 'center' && options.position.y == 'center') options.edge = {x:'center', y:'center'};
			else options.edge = {x:'left', y:'top'};
		}

		this.setStyle('position', 'absolute');
		var rel = $(options.relativeTo) || document.body;
		var calc = rel == document.body ? window.getScroll() : rel.getPosition();
		var top = calc.y;
		var left = calc.x;

		if (Browser.Engine.trident){
			var scrolls = rel.getScrolls();
			top += scrolls.y;
			left += scrolls.x;
		}

		var dim = this.getDimensions({computeSize: true, styles:['padding', 'border','margin']});
		if (options.ignoreMargins){
			options.offset.x = options.offset.x - dim['margin-left'];
			options.offset.y = options.offset.y - dim['margin-top'];
		}
		var pos = {};
		var prefY = options.offset.y;
		var prefX = options.offset.x;
		var winSize = window.getSize();
		switch(options.position.x){
			case 'left':
				pos.x = left + prefX;
				break;
			case 'right':
				pos.x = left + prefX + rel.offsetWidth;
				break;
			default: //center
				pos.x = left + ((rel == document.body ? winSize.x : rel.offsetWidth)/2) + prefX;
				break;
		};
		switch(options.position.y){
			case 'top':
				pos.y = top + prefY;
				break;
			case 'bottom':
				pos.y = top + prefY + rel.offsetHeight;
				break;
			default: //center
				pos.y = top + ((rel == document.body ? winSize.y : rel.offsetHeight)/2) + prefY;
				break;
		};

		if (options.edge){
			var edgeOffset = {};

			switch(options.edge.x){
				case 'left':
					edgeOffset.x = 0;
					break;
				case 'right':
					edgeOffset.x = -dim.x-dim.computedRight-dim.computedLeft;
					break;
				default: //center
					edgeOffset.x = -(dim.x/2);
					break;
			};
			switch(options.edge.y){
				case 'top':
					edgeOffset.y = 0;
					break;
				case 'bottom':
					edgeOffset.y = -dim.y-dim.computedTop-dim.computedBottom;
					break;
				default: //center
					edgeOffset.y = -(dim.y/2);
					break;
			};
			pos.x = pos.x + edgeOffset.x;
			pos.y = pos.y + edgeOffset.y;
		}
		pos = {
			left: ((pos.x >= 0 || parentPositioned || options.allowNegative) ? pos.x : 0).toInt(),
			top: ((pos.y >= 0 || parentPositioned || options.allowNegative) ? pos.y : 0).toInt()
		};
		if (rel.getStyle('position') == "fixed" || options.relFixedPosition){
			var winScroll = window.getScroll();
			pos.top = pos.top.toInt() + winScroll.y;
			pos.left = pos.left.toInt() + winScroll.x;
		}

		if (options.returnPos) return pos;
		else this.setStyles(pos);
		return this;
	}

});


/*
Script: Element.Shortcuts.js
	Extends the Element native object to include some shortcut methods.

License:
	http://www.clientcide.com/wiki/cnet-libraries#license
*/

Element.implement({
	isVisible: function() {
		return this.getStyle('display') != 'none';
	},
	toggle: function() {
		return this[this.isVisible() ? 'hide' : 'show']();
	},
	hide: function() {
		var d;
		try {
			//IE fails here if the element is not in the dom
			if ('none' != this.getStyle('display')) d = this.getStyle('display');
		} catch(e){}
		this.store('originalDisplay', d||'block');
		this.setStyle('display','none');
		return this;
	},
	show: function(display) {
		original = this.retrieve('originalDisplay')?this.retrieve('originalDisplay'):this.get('originalDisplay');
		this.setStyle('display',(display || original || 'block'));
		return this;
	},
	swapClass: function(remove, add) {
		return this.removeClass(remove).addClass(add);
	},
	//TODO
	//DO NOT USE THIS METHOD
	//it is temporary, as Mootools 1.1 will negate its requirement
	fxOpacityOk: function(){
		return !Browser.Engine.trident4;
	}
});


/*
Script: modalizer.js
	Defines Modalizer: functionality to overlay the window contents with a semi-transparent layer that prevents interaction with page content until it is removed

License:
	http://www.clientcide.com/wiki/cnet-libraries#license
*/
var Modalizer = new Class({
	defaultModalStyle: {
		display:'block',
		position:'fixed',
		top:0,
		left:0,
		'z-index':5000,
		'background-color':'#444',
		opacity:0.8
	},
	setModalOptions: function(options){
		this.modalOptions = $merge({
			width:(window.getScrollSize().x+300),
			height:(window.getScrollSize().y+300),
			elementsToHide: 'select',
			hideOnClick: true,
			modalStyle: {},
			updateOnResize: true,
			layerId: 'modalOverlay',
			onModalHide: $empty,
			onModalShow: $empty
		}, this.modalOptions, options);
		return this;
	},
	layer: function(){
		if (!this.modalOptions.layerId) this.setModalOptions();
		return $(this.modalOptions.layerId) || new Element('div', {id: this.modalOptions.layerId}).inject(document.body);
	},
	resize: function(){
		if(this.layer()) {
			this.layer().setStyles({
				width:(window.getScrollSize().x+300),
				height:(window.getScrollSize().y+300)
			});
		}
	},
	setModalStyle: function (styleObject){
		this.modalOptions.modalStyle = styleObject;
		this.modalStyle = $merge(this.defaultModalStyle, {
			width:this.modalOptions.width,
			height:this.modalOptions.height
		}, styleObject);
		if(this.layer()) this.layer().setStyles(this.modalStyle);
		return(this.modalStyle);
	},
	modalShow: function(options){
		this.setModalOptions(options);
		this.layer().setStyles(this.setModalStyle(this.modalOptions.modalStyle));
		if(Browser.Engine.trident4) this.layer().setStyle('position','absolute');
		this.layer().removeEvents('click').addEvent('click', function(){
			this.modalHide(this.modalOptions.hideOnClick);
		}.bind(this));
		this.bound = this.bound||{};
		if(!this.bound.resize && this.modalOptions.updateOnResize) {
			this.bound.resize = this.resize.bind(this);
			window.addEvent('resize', this.bound.resize);
		}
		if ($type(this.modalOptions.onModalShow)  == "function") this.modalOptions.onModalShow();
		this.togglePopThroughElements(0);
		this.layer().setStyle('display','block');
		return this;
	},
	modalHide: function(override, force){
		if(override === false) return false; //this is internal, you don't need to pass in an argument
		this.togglePopThroughElements(1);
		if ($type(this.modalOptions.onModalHide) == "function") this.modalOptions.onModalHide();
		this.layer().setStyle('display','none');
		if(this.modalOptions.updateOnResize) {
			this.bound = this.bound||{};
			if(!this.bound.resize) this.bound.resize = this.resize.bind(this);
			window.removeEvent('resize', this.bound.resize);
		}
		return this;
	},
	togglePopThroughElements: function(opacity){
		if(Browser.Engine.trident4 || (Browser.Engine.gecko && Browser.Platform.mac)) {
			$$(this.modalOptions.elementsToHide).each(function(sel){
				sel.setStyle('opacity', opacity);
			});
		}
	}
});

/*
Script: StyleWriter.js

Provides a simple method for injecting a css style element into the DOM if it's not already present.

License:
	http://www.clientcide.com/wiki/cnet-libraries#license
*/

var StyleWriter = new Class({
	createStyle: function(css, id) {
		window.addEvent('domready', function(){
			try {
				if($(id) && id) return;
				var style = new Element('style', {id: id||''}).inject($$('head')[0]);
				if (Browser.Engine.trident) style.styleSheet.cssText = css;
				else style.set('text', css);
			}catch(e){dbug.log('error: %s',e);}
		}.bind(this));
	}
});

/*
Script: StickyWin.js

Creates a div within the page with the specified contents at the location relative to the element you specify; basically an in-page popup maker.

License:
	http://www.clientcide.com/wiki/cnet-libraries#license
*/

var StickyWin = new Class({
	Implements: [Options, Events, StyleWriter, ToElement],
	options: {
//		onDisplay: $empty,
//		onClose: $empty,
		closeClassName: 'closeSticky',
		pinClassName: 'pinSticky',
		content: '',
		zIndex: 10000,
		className: '',
//		id: ... set above in initialize function
/*  	these are the defaults for setPosition anyway
		************************************************
		edge: false, //see Element.setPosition
		position: 'center', //center, corner == upperLeft, upperRight, bottomLeft, bottomRight
		offset: {x:0,y:0},
		relativeTo: document.body, */
		width: false,
		height: false,
		timeout: -1,
		allowMultipleByClass: false,
		allowMultiple: true,
		showNow: true,
		useIframeShim: true,
		iframeShimSelector: ''
	},
	css: '.SWclearfix:after {content: "."; display: block; height: 0; clear: both; visibility: hidden;}'+
			 '.SWclearfix {display: inline-table;}'+
			 '* html .SWclearfix {height: 1%;}'+
			 '.SWclearfix {display: block;}',
	initialize: function(options){
		this.options.inject = {
			target: document.body,
			where: 'bottom'
		};
		this.setOptions(options);

		this.id = this.options.id || 'StickyWin_'+new Date().getTime();
		this.makeWindow();

		if(this.options.content) this.setContent(this.options.content);
		if(this.options.timeout > 0) {
			this.addEvent('onDisplay', function(){
				this.hide.delay(this.options.timeout, this)
			}.bind(this));
		}
		if(this.options.showNow) this.show();
		//add css for clearfix
		this.createStyle(this.css, 'StickyWinClearFix');
	},
	makeWindow: function(){
		this.destroyOthers();
		if(!$(this.id)) {
			this.win = new Element('div', {
				id:		this.id
			}).addClass(this.options.className).addClass('StickyWinInstance').addClass('SWclearfix').setStyles({
			 	display:'none',
				position:'absolute',
				zIndex:this.options.zIndex
			}).inject(this.options.inject.target, this.options.inject.where).store('StickyWin', this);
		} else this.win = $(this.id);
		this.element = this.win;
		if(this.options.width && $type(this.options.width.toInt())=="number") this.win.setStyle('width', this.options.width.toInt());
		if(this.options.height && $type(this.options.height.toInt())=="number") this.win.setStyle('height', this.options.height.toInt());
		return this;
	},
	show: function(suppressEvent){
		this.showWin();
		if (!suppressEvent) this.fireEvent('onDisplay');
		if(this.options.useIframeShim) this.showIframeShim();
		this.visible = true;
		return this;
	},
	showWin: function(){
		if(!this.positioned) this.position();
		this.win.show();
	},
	hide: function(suppressEvent){
		if(!suppressEvent) this.fireEvent('onClose');
		this.hideWin();
		if(this.options.useIframeShim) this.hideIframeShim();
		this.visible = false;
		return this;
	},
	hideWin: function(){
		this.win.setStyle('display','none');
	},
	destroyOthers: function() {
		if(!this.options.allowMultipleByClass || !this.options.allowMultiple) {
			$$('div.StickyWinInstance').each(function(sw) {
				if(!this.options.allowMultiple || (!this.options.allowMultipleByClass && sw.hasClass(this.options.className)))
					sw.retrieve('StickyWin').destroy();
			}, this);
		}
	},
	setContent: function(html) {
		if(this.win.getChildren().length>0) this.win.empty();
		if($type(html) == "string") this.win.set('html', html);
		else if ($(html)) this.win.adopt(html);
		this.win.getElements('.'+this.options.closeClassName).each(function(el){
			el.addEvent('click', this.hide.bind(this));
		}, this);
		this.win.getElements('.'+this.options.pinClassName).each(function(el){
			el.addEvent('click', this.togglepin.bind(this));
		}, this);
		return this;
	},
	position: function(options){
		this.positioned = true;
		this.setOptions(options);
		this.win.setPosition({
			allowNegative: true,
			relativeTo: this.options.relativeTo,
			position: this.options.position,
			offset: this.options.offset,
			edge: this.options.edge
		});
		if(this.shim) this.shim.position();
		return this;
	},
	pin: function(pin) {
		if(!this.win.pin) {
			dbug.log('you must include element.pin.js!');
			return this;
		}
		this.pinned = $pick(pin, true);
		this.win.pin(pin);
		return this;
	},
	unpin: function(){
		return this.pin(false);
	},
	togglepin: function(){
		return this.pin(!this.pinned);
	},
	makeIframeShim: function(){
		if(!this.shim){
			var el = (this.options.iframeShimSelector)?this.win.getElement(this.options.iframeShimSelector):this.win;
			this.shim = new IframeShim(el, {
				display: false,
				name: 'StickyWinShim'
			});
		}
	},
	showIframeShim: function(){
		if(this.options.useIframeShim) {
			this.makeIframeShim();
			this.shim.show();
		}
	},
	hideIframeShim: function(){
		if(this.shim) this.shim.hide();
	},
	destroy: function(){
		if (this.win) this.win.dispose();
		if(this.options.useIframeShim && this.shim) this.shim.dispose();
		if($('modalOverlay'))$('modalOverlay').dispose();
	}
});


/*
Script: StickyWin.Modal.js

This script extends StickyWin and StickyWin.Fx classes to add Modalizer functionality.

License:
	http://www.clientcide.com/wiki/cnet-libraries#license
*/
(function(){
var modalWinBase = function(extend){
	return {
		Extends: extend,
		initialize: function(options){
			options = options||{};
			this.setModalOptions($merge(options.modalOptions||{}, {
				onModalHide: function(){
						this.hide(false);
					}.bind(this)
				}));
			this.parent(options);
		},
		show: function(showModal){
			if($pick(showModal, true)) {
				this.modalShow();
				if (this.modalOptions.elementsToHide) this.win.getElements(this.modalOptions.elementsToHide).setStyle('opacity', 1);
			}
			this.parent();
		},
		hide: function(hideModal){
			if($pick(hideModal, true)) this.modalHide();
			this.parent();
		}
	}
};

StickyWin.Modal = new Class(modalWinBase(StickyWin));
StickyWin.Modal.implement(new Modalizer());
})();
//legacy
var StickyWinModal = StickyWin.Modal;

/*
Script: piechart.js

Dependencies:
	mootools-beta-1.2b2.js
	moocanvas.js

Author:
	Greg Houston, <http://greghoustondesign.com/>

Credits:
	Based on Stoyan Stefanov's Canvas Pie:< http://www.phpied.com/canvas-pie/>
	Color algorithm inspired by Jim Bumgardner:<http://www.krazydad.com/makecolors.php>

License:
	MIT License, <http://en.wikipedia.org/wiki/MIT_License>

Example Usage:

<table class="pieChart">
    <tr><th>Browser</th> <th>Value</th></tr>
    <tr><td>Safari </td> <td>180  </td></tr>
    <tr><td>Firefox</td> <td>210  </td></tr>
    <tr><td>IE     </td> <td>30   </td></tr>
    <tr><td>Opera  </td> <td>120  </td></tr>
</table>

*/


var PieChart = new Class({
	options: {
		pieChartRadius: 60,  // Half the width of your pie chart
    	td_label_index: 0,    // which TD contains the label
    	td_index: 1,           // which TD contains the data
    	index: 1
	},
	initialize: function(elData,el,options){
		this.setOptions(options);

		// Initialize variables
		this.pieChartRadius = this.options.pieChartRadius;
		this.pieChartDiameter = this.pieChartRadius * 2;
		this.pieVertices = 12; // Does not include the center vertex
		this.arcIncrementMultiplier = 1 / this.pieVertices;
		this.index = 0;
		this.tableIndex = this.options.index;
		this.areaIndex = 1;
		this.canvas = '';
		this.container = '';
		this.data_table = '';


		this.insertElements(el);
    	aData=this.makeData(elData);
		this.makePieChart(aData);
		this.addToolTips();
	},
	insertElements: function(el){

    	///// STEP 1 - Insert HTML Elements

		// Insert a div that will contain both the pie chart and it's legend
		this.container = new Element('div', {
			id: 'pieChartContainer' + this.tableIndex
		}).injectBefore($(el)).addClass('pieChartContainer');

		// Pull the table out of the page and put it in the pie chart container
		this.data_table = el.clone().injectBottom(this.container);
		el.dispose();

		// Insert a div that will contain both the pie chart canvas and it's image map overlay
		new Element('div', {
			id: 'pieChartWrapper' + this.tableIndex
		}).injectTop(this.container).addClass('pieChartWrapper');

		// Insert the canvas to draw the pie on
		this.canvas = new Element('canvas', {
			id: 'canvas' + this.tableIndex,
			width: this.pieChartDiameter,
			height: this.pieChartDiameter
		}).injectInside(this.container.getElement('.pieChartWrapper')).addClass('pieChartCanvas');

		// Insert the map element. The area elements will be added later
		new Element('map', {
			id: 'pieChartMap' + this.tableIndex,
			name: 'pieChartMap' + this.tableIndex
		}).injectBottom(this.container).addClass('pieChartMap');

		// Insert the blank transparent gif that is used for the image map
		new Asset.image(DIR_STATIC_SKIN+'/images/spacer.gif', {
			alt: '',
			usemap: '#pieChartMap' + this.tableIndex,
			width: this.pieChartDiameter,
			height: this.pieChartDiameter
		}).injectInside(this.container.getElement('.pieChartWrapper')).setStyles({
				'width': this.pieChartDiameter,
				'height': this.pieChartDiameter
			});

		// Insert a div to insure layout integrity
		new Element('div').injectBottom(this.container).addClass('clear');

	},
	makeData: function(elData) {
		var aData=[];
		elData.getChildren().each(function(el) {
			var data=el.getChildren();
			if ($(data[0])) {
				var color = data[0].getStyle('background').match(/#\w+/i);
				aData.extend([{
					'label': el.get('text'),
    				'value': data[1].get('text'),
    				'color': data[0].getStyle('background').match(/#\w+/i)[0]
				}]);
			}
		});
		return aData;
	},
	makePieChart: function(aData){

    	///// STEP 2 - Get the data
    	var  data = [], color, colors = [], labels = [], values = [], total = 0, value=0;
    	aData.each(function(item, index){
			labels[colors.length] = item.label;
			value=parseFloat(item.value);
			values[colors.length] = value;
        	total += value;
        	colors[colors.length] = item.color.hexToRgb();
		},this);

    	///// STEP 3 - Draw pie on canvas

    	// get canvas context, determine radius and center
    	var ctx = this.canvas.getContext('2d');

		var tableLength = colors.length;
    	for (piece=0; piece < tableLength; piece++) {

        	var thisvalue = values[piece] / total;
			var arcStartAngle = Math.PI * (- 0.5 + 2 * this.index); // -0.5 sets set the start to be top
			var arcEndAngle = Math.PI * (- 0.5 + 2 * (this.index + thisvalue));

			ctx.beginPath();
			ctx.moveTo(this.pieChartRadius, this.pieChartRadius); // Center of the pie
			ctx.arc(  // draw next arc
            	this.pieChartRadius,
            	this.pieChartRadius,
            	this.pieChartRadius,
            	arcStartAngle,
            	arcEndAngle,
            	false
        	);
        	ctx.closePath();
        	ctx.fillStyle = colors[piece]; // Color
        	ctx.fill();

			// Draw the same thing again to draw stroke properly in IE
			ctx.lineWidth = 1;
        	ctx.beginPath();
        	ctx.moveTo(this.pieChartRadius, this.pieChartRadius);

        	ctx.arc(  // draw next arc
            	this.pieChartRadius,
            	this.pieChartRadius,
            	this.pieChartRadius,
            	arcStartAngle,
            	arcEndAngle,
            	false
        	);
        	ctx.closePath();
			ctx.strokeStyle = "#FFF";
			ctx.stroke();

    		///// STEP 4 - Draw pie on image map

			var arcIncrement = (arcEndAngle - arcStartAngle) * this.arcIncrementMultiplier;

			var xx = this.pieChartRadius + Math.round(Math.cos(arcStartAngle) * this.pieChartRadius);
			var yy = this.pieChartRadius + Math.round(Math.sin(arcStartAngle) * this.pieChartRadius);

			var coord = [];
			var coordIndex = 1;

			for (i = 0; i < ((this.pieVertices * 2) - 2); i = i+2) {
				var arcAngle = arcStartAngle + arcIncrement * coordIndex;
				coord[i] = this.pieChartRadius + Math.round(Math.cos(arcAngle) * this.pieChartRadius);
				coord[i+1] = this.pieChartRadius + Math.round(Math.sin(arcAngle) * this.pieChartRadius);
				coordIndex++;
			}

			var xxEnd = this.pieChartRadius + Math.round(Math.cos(arcEndAngle) * this.pieChartRadius);
			var yyEnd = this.pieChartRadius + Math.round(Math.sin(arcEndAngle) * this.pieChartRadius);

			var myArea = 'area' + this.tableIndex + '-' + piece;

			new Element('area', {
				'id': myArea ,
				'shape': 'poly',
				'coords': this.pieChartRadius + ',' + this.pieChartRadius + ',' + + xx + ',' + yy + ',' + coord.join(',') +  ',' + xxEnd + ',' + yyEnd,
				'title': labels[piece]
			}).injectInside(this.container.getElement('.pieChartMap'));

        	this.index += thisvalue; // increment progress tracker
    	}

	this.tableIndex++;

	},
	addToolTips: function(){

    		///// STEP 5 - Add Tooltips

			new Tips($$(document.getElementsByTagName('area')), {
				showDelay: 10,
				hideDelay: 10
			});

	},
	getColor: function(i, totalSteps){
		var colori = i * 100 / totalSteps;
		var frequency = Math.PI*2 / totalSteps;
		var center = 190;
		var amplitude = 60;
        var rgb = [];
		rgb[0]   = Math.round(Math.sin(frequency * i + 0) * amplitude + center);
		rgb[1] = Math.round(Math.sin(frequency * i + 2) * amplitude + center);
		rgb[2]  = Math.round(Math.sin(frequency * i + 4) * amplitude + center);
		return 'rgb(' + rgb.join(',') + ')';
	}
});
PieChart.implement(new Options);

/**
 * Roar - Notifications
 *
 * Inspired by Growl
 *
 * @version		1.0.1
 *
 * @license		MIT-style license
 * @author		Harald Kirschner <mail [at] digitarald.de>
 * @copyright	Author
 */

var Roar = new Class({

	Implements: [Options, Events, Chain],

	options: {
		duration: 4000,
		position: 'upperLeft',
		container: null,
		bodyFx: null,
		itemFx: null,
		margin: {x: 10, y: 10},
		offset: 5,
		className: 'roar',
		onShow: $empty,
		onHide: $empty,
		onRender: $empty,
		style: 'notice'
	},

	initialize: function(options) {
		this.setOptions(options);
		this.items = [];
		this.container = $(this.options.container) || document;
	},

	alert: function(title, message, options) {
		var params = Array.link(arguments, {title: String.type, message: String.type, options: Object.type});
		var items = [new Element('h3', {'html': $pick(params.title, '')})];
		if (params.message) items.push(new Element('p', {'html': params.message}));
		return this.inject(items, params.options);
	},

	inject: function(elements, options) {
		if (!this.body) this.render();
		options = options || {};

		var offset = [-this.options.offset, 0];
		var last = this.items.getLast();
		if (last) {
			offset[0] = last.retrieve('roar:offset');
			offset[1] = offset[0] + last.offsetHeight + this.options.offset;
		}
		var to = {'opacity': 1};
		to[this.align.y] = offset;

		var item = new Element('div', {
			'class': this.options.className,
			'opacity': 0
		}).adopt(
			new Element('div', {
				'class': this.options.className+'-bg',
				'opacity': 0.7
			}),
			elements
		);

		item.setStyle(this.align.x, 0).store('roar:offset', offset[1]).set('morph', $merge({
			unit: 'px',
			link: 'cancel',
			onStart: Chain.prototype.clearChain,
			transition: Fx.Transitions.Back.easeOut
		}, this.options.itemFx));

		var remove = this.remove.create({
			bind: this,
			arguments: [item],
			delay: 10
		});
		this.items.push(item.addEvent('click', remove));

		if (this.options.duration) {
			var over = false;
			var trigger = (function() {
				trigger = null;
				if (!over) remove();
			}).delay(this.options.duration);
			item.addEvents({
				mouseover: function() {
					over = true;
				},
				mouseout: function() {
					over = false;
					if (!trigger) remove();
				}
			});
		}
		item.inject(this.body).morph(to);
		return this.fireEvent('onShow', [item, this.items.length]);
	},

	remove: function(item) {
		var index = this.items.indexOf(item);
		if (index == -1) return this;
		this.items.splice(index, 1);
		item.removeEvents();
		var to = {opacity: 0};
		to[this.align.y] = item.getStyle(this.align.y).toInt() - item.offsetHeight - this.options.offset;
		item.morph(to).get('morph').chain(item.destroy.bind(item));
		return this.fireEvent('onHide', [item, this.items.length]).callChain(item);
	},

	empty: function() {
		while (this.items.length) this.remove(this.items[0]);
		return this;
	},

	render: function() {
		this.position = this.options.position;
		if ($type(this.position) == 'string') {
			var position = {x: 'center', y: 'center'};
			this.align = {x: 'left', y: 'top'};
			if ((/left|west/i).test(this.position)) position.x = 'left';
			else if ((/right|east/i).test(this.position)) this.align.x = position.x = 'right';
			if ((/upper|top|north/i).test(this.position)) position.y = 'top';
			else if ((/bottom|lower|south/i).test(this.position)) this.align.y = position.y = 'bottom';
			this.position = position;
		}
		this.body = new Element('div', {'class': this.options.className+'-body'}).inject(document.body);
		if (Browser.Engine.trident4) this.body.addClass(this.options.className+'-body-ugly');
		this.moveTo = this.body.setStyles.bind(this.body);
		this.reposition();
		if (this.options.bodyFx) {
			var morph = new Fx.Morph(this.body, $merge({
				unit: 'px',
				chain: 'cancel',
				transition: Fx.Transitions.Circ.easeOut
			}, this.options.bodyFx));
			this.moveTo = morph.start.bind(morph);
		}
		var repos = this.reposition.bind(this);
		window.addEvents({
			scroll: repos,
			resize: repos
		});
		this.fireEvent('onRender', this.body);
	},

	reposition: function() {
		var max = document.getCoordinates(), scroll = document.getScroll(), margin = this.options.margin;
		max.left += scroll.x;
		max.right += scroll.x;
		max.top += scroll.y;
		max.bottom += scroll.y;
		var rel = ($type(this.container) == 'element') ? this.container.getCoordinates() : max;
		this.moveTo({
			left: (this.position.x == 'right')
				? (Math.min(rel.right, max.right) - margin.x)
				: (Math.max(rel.left, max.left) + margin.x),
			top: (this.position.y == 'bottom')
				? (Math.min(rel.bottom, max.bottom) - margin.y)
				: (Math.max(rel.top, max.top) + margin.y)
		});
	}

});
