/*
 * jQuery JavaScript Library v1.3.2
 * http://jquery.com/
 *
 * Copyright (c) 2009 John Resig
 * Dual licensed under the MIT and GPL licenses.
 * http://docs.jquery.com/License
 *
 * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
 * Revision: 6246
 */
(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F<J;F++){var G=M[F];if(G.selected){K=o(G).val();if(H){return K}L.push(K)}}return L}return(E.value||"").replace(/\r/g,"")}return g}if(typeof K==="number"){K+=""}return this.each(function(){if(this.nodeType!=1){return}if(o.isArray(K)&&/radio|checkbox/.test(this.type)){this.checked=(o.inArray(this.value,K)>=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G<E;G++){L.call(K(this[G],H),this.length>1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H<I;H++){if((G=arguments[H])!=null){for(var F in G){var K=J[F],L=G[F];if(J===L){continue}if(E&&L&&typeof L==="object"&&!L.nodeType){J[F]=o.extend(E,K||(L.length!=null?[]:{}),L)}else{if(L!==g){J[F]=L}}}}}return J};var b=/z-?index|font-?weight|opacity|zoom|line-?height/i,q=document.defaultView||{},s=Object.prototype.toString;o.extend({noConflict:function(E){l.$=p;if(E){l.jQuery=y}return o},isFunction:function(E){return s.call(E)==="[object Function]"},isArray:function(E){return s.call(E)==="[object Array]"},isXMLDoc:function(E){return E.nodeType===9&&E.documentElement.nodeName!=="HTML"||!!E.ownerDocument&&o.isXMLDoc(E.ownerDocument)},globalEval:function(G){if(G&&/\S/.test(G)){var F=document.getElementsByTagName("head")[0]||document.documentElement,E=document.createElement("script");E.type="text/javascript";if(o.support.scriptEval){E.appendChild(document.createTextNode(G))}else{E.text=G}F.insertBefore(E,F.firstChild);F.removeChild(E)}},nodeName:function(F,E){return F.nodeName&&F.nodeName.toUpperCase()==E.toUpperCase()},each:function(G,K,F){var E,H=0,I=G.length;if(F){if(I===g){for(E in G){if(K.apply(G[E],F)===false){break}}}else{for(;H<I;){if(K.apply(G[H++],F)===false){break}}}}else{if(I===g){for(E in G){if(K.call(G[E],E,G[E])===false){break}}}else{for(var J=G[0];H<I&&K.call(J,H,J)!==false;J=G[++H]){}}}return G},prop:function(H,I,G,F,E){if(o.isFunction(I)){I=I.call(H,F)}return typeof I==="number"&&G=="curCSS"&&!b.test(E)?I+"px":I},className:{add:function(E,F){o.each((F||"").split(/\s+/),function(G,H){if(E.nodeType==1&&!o.className.has(E.className,H)){E.className+=(E.className?" ":"")+H}})},remove:function(E,F){if(E.nodeType==1){E.className=F!==g?o.grep(E.className.split(/\s+/),function(G){return !o.className.has(F,G)}).join(" "):""}},has:function(F,E){return F&&o.inArray(E,(F.className||F).toString().split(/\s+/))>-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+"></"+T+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!O.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!O.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!O.indexOf("<td")||!O.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!O.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||!o.support.htmlSerialize&&[1,"div<div>","</div>"]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/<tbody/i.test(S),N=!O.indexOf("<table")&&!R?L.firstChild&&L.firstChild.childNodes:Q[1]=="<table>"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E<F;E++){if(H[E]===G){return E}}return -1},merge:function(H,E){var F=0,G,I=H.length;if(!o.support.getAll){while((G=E[F++])!=null){if(G.nodeType!=8){H[I++]=G}}}else{while((G=E[F++])!=null){H[I++]=G}}return H},unique:function(K){var F=[],E={};try{for(var G=0,H=K.length;G<H;G++){var J=o.data(K[G]);if(!E[J]){E[J]=true;F.push(K[G])}}}catch(I){F=K}return F},grep:function(F,J,E){var G=[];for(var H=0,I=F.length;H<I;H++){if(!E!=!J(F[H],H)){G.push(F[H])}}return G},map:function(E,J){var F=[];for(var G=0,H=E.length;G<H;G++){var I=J(E[G],G);if(I!=null){F[F.length]=I}}return F.concat.apply([],F)}});var C=navigator.userAgent.toLowerCase();o.browser={version:(C.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[0,"0"])[1],safari:/webkit/.test(C),opera:/opera/.test(C),msie:/msie/.test(C)&&!/opera/.test(C),mozilla:/mozilla/.test(C)&&!/(compatible|webkit)/.test(C)};o.each({parent:function(E){return E.parentNode},parents:function(E){return o.dir(E,"parentNode")},next:function(E){return o.nth(E,2,"nextSibling")},prev:function(E){return o.nth(E,2,"previousSibling")},nextAll:function(E){return o.dir(E,"nextSibling")},prevAll:function(E){return o.dir(E,"previousSibling")},siblings:function(E){return o.sibling(E.parentNode.firstChild,E)},children:function(E){return o.sibling(E.firstChild)},contents:function(E){return o.nodeName(E,"iframe")?E.contentDocument||E.contentWindow.document:o.makeArray(E.childNodes)}},function(E,F){o.fn[E]=function(G){var H=o.map(this,F);if(G&&typeof G=="string"){H=o.multiFilter(G,H)}return this.pushStack(o.unique(H),E,G)}});o.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(E,F){o.fn[E]=function(G){var J=[],L=o(G);for(var K=0,H=L.length;K<H;K++){var I=(K>0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}});
/*
 * Sizzle CSS Selector Engine - v0.9.3
 *  Copyright 2009, The Dojo Foundation
 *  Released under the MIT, BSD, and GPL Licenses.
 *  More information: http://sizzlejs.com/
 */
(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa<ab.length;aa++){if(ab[aa]===ab[aa-1]){ab.splice(aa--,1)}}}}}return ab};F.matches=function(T,U){return F(T,null,null,U)};F.find=function(aa,T,ab){var Z,X;if(!aa){return[]}for(var W=0,V=I.order.length;W<V;W++){var Y=I.order[W],X;if((X=I.match[Y].exec(aa))){var U=RegExp.leftContext;if(U.substr(U.length-1)!=="\\"){X[1]=(X[1]||"").replace(/\\/g,"");Z=I.find[Y](X,T,ab);if(Z!=null){aa=aa.replace(I.match[Y],"");break}}}}if(!Z){Z=T.getElementsByTagName("*")}return{set:Z,expr:aa}};F.filter=function(ad,ac,ag,W){var V=ad,ai=[],aa=ac,Y,T,Z=ac&&ac[0]&&Q(ac[0]);while(ad&&ac.length){for(var ab in I.filter){if((Y=I.match[ab].exec(ad))!=null){var U=I.filter[ab],ah,af;T=false;if(aa==ai){ai=[]}if(I.preFilter[ab]){Y=I.preFilter[ab](Y,aa,ag,ai,W,Z);if(!Y){T=ah=true}else{if(Y===true){continue}}}if(Y){for(var X=0;(af=aa[X])!=null;X++){if(af){ah=U(af,Y,X,aa);var ae=W^!!ah;if(ag&&ah!=null){if(ae){T=true}else{aa[X]=false}}else{if(ae){ai.push(af);T=true}}}}}if(ah!==g){if(!ag){aa=ai}ad=ad.replace(I.match[ab],"");if(!T){return[]}break}}}if(ad==V){if(T==null){throw"Syntax error, unrecognized expression: "+ad}else{break}}V=ad}return aa};var I=F.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(T){return T.getAttribute("href")}},relative:{"+":function(aa,T,Z){var X=typeof T==="string",ab=X&&!/\W/.test(T),Y=X&&!ab;if(ab&&!Z){T=T.toUpperCase()}for(var W=0,V=aa.length,U;W<V;W++){if((U=aa[W])){while((U=U.previousSibling)&&U.nodeType!==1){}aa[W]=Y||U&&U.nodeName===T?U||false:U===T}}if(Y){F.filter(T,aa,true)}},">":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){var W=Y.parentNode;Z[V]=W.nodeName===U?W:false}}}else{for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){Z[V]=X?Y.parentNode:Y.parentNode===U}}if(X){F.filter(U,Z,true)}}},"":function(W,U,Y){var V=L++,T=S;if(!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("parentNode",U,V,W,X,Y)},"~":function(W,U,Y){var V=L++,T=S;if(typeof U==="string"&&!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("previousSibling",U,V,W,X,Y)}},find:{ID:function(U,V,W){if(typeof V.getElementById!=="undefined"&&!W){var T=V.getElementById(U[1]);return T?[T]:[]}},NAME:function(V,Y,Z){if(typeof Y.getElementsByName!=="undefined"){var U=[],X=Y.getElementsByName(V[1]);for(var W=0,T=X.length;W<T;W++){if(X[W].getAttribute("name")===V[1]){U.push(X[W])}}return U.length===0?null:U}},TAG:function(T,U){return U.getElementsByTagName(T[1])}},preFilter:{CLASS:function(W,U,V,T,Z,aa){W=" "+W[1].replace(/\\/g,"")+" ";if(aa){return W}for(var X=0,Y;(Y=U[X])!=null;X++){if(Y){if(Z^(Y.className&&(" "+Y.className+" ").indexOf(W)>=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return U<T[3]-0},gt:function(V,U,T){return U>T[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W<T;W++){if(Y[W]===Z){return false}}return true}}}},CHILD:function(T,W){var Z=W[1],U=T;switch(Z){case"only":case"first":while(U=U.previousSibling){if(U.nodeType===1){return false}}if(Z=="first"){return true}U=T;case"last":while(U=U.nextSibling){if(U.nodeType===1){return false}}return true;case"nth":var V=W[2],ac=W[3];if(V==1&&ac==0){return true}var Y=W[0],ab=T.parentNode;if(ab&&(ab.sizcache!==Y||!T.nodeIndex)){var X=0;for(U=ab.firstChild;U;U=U.nextSibling){if(U.nodeType===1){U.nodeIndex=++X}}ab.sizcache=Y}var aa=T.nodeIndex-ac;if(V==0){return aa==0}else{return(aa%V==0&&aa/V>=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V<T;V++){U.push(X[V])}}else{for(var V=0;X[V];V++){U.push(X[V])}}}return U}}var G;if(document.documentElement.compareDocumentPosition){G=function(U,T){var V=U.compareDocumentPosition(T)&4?-1:U===T?0:1;if(V===0){hasDuplicate=true}return V}}else{if("sourceIndex" in document.documentElement){G=function(U,T){var V=U.sourceIndex-T.sourceIndex;if(V===0){hasDuplicate=true}return V}}else{if(document.createRange){G=function(W,U){var V=W.ownerDocument.createRange(),T=U.ownerDocument.createRange();V.selectNode(W);V.collapse(true);T.selectNode(U);T.collapse(true);var X=V.compareBoundaryPoints(Range.START_TO_END,T);if(X===0){hasDuplicate=true}return X}}}}(function(){var U=document.createElement("form"),V="script"+(new Date).getTime();U.innerHTML="<input name='"+V+"'/>";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="<a href='#'></a>";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="<p class='TEST'></p>";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="<div class='test e'></div><div class='test'></div>";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1&&!ac){T.sizcache=Y;T.sizset=W}if(T.nodeName===Z){X=T;break}T=T[U]}ad[W]=X}}}function S(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1){if(!ac){T.sizcache=Y;T.sizset=W}if(typeof Z!=="string"){if(T===Z){X=true;break}}else{if(F.filter(Z,[T]).length>0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z<U;Z++){F(T,V[Z],W)}return F.filter(X,W)};o.find=F;o.filter=F.filter;o.expr=F.selectors;o.expr[":"]=o.expr.filters;F.selectors.filters.hidden=function(T){return T.offsetWidth===0||T.offsetHeight===0};F.selectors.filters.visible=function(T){return T.offsetWidth>0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F<E.length){o.event.proxy(G,E[F++])}return this.click(o.event.proxy(G,function(H){this.lastToggle=(this.lastToggle||0)%F;H.preventDefault();return E[this.lastToggle++].apply(this,arguments)||false}))},hover:function(E,F){return this.mouseenter(E).mouseleave(F)},ready:function(E){B();if(o.isReady){E.call(document,o)}else{o.readyList.push(E)}return this},live:function(G,F){var E=o.event.proxy(F);E.guid+=this.selector+G;o(document).bind(i(G,this.selector),this.selector,E);return this},die:function(F,E){o(document).unbind(i(F,this.selector),E?{guid:E.guid+this.selector+F}:null);return this}});function c(H){var E=RegExp("(^|\\.)"+H.type+"(\\.|$)"),G=true,F=[];o.each(o.data(this,"events").live||[],function(I,J){if(E.test(J.type)){var K=o(H.target).closest(J.data)[0];if(K){F.push({elem:K,fn:J})}}});F.sort(function(J,I){return o.data(J.elem,"closest")-o.data(I.elem,"closest")});o.each(F,function(){if(this.fn.call(this.elem,H,this.fn.data)===false){return(G=false)}});return G}function i(F,E){return["live",F,E.replace(/\./g,"`").replace(/ /g,"|")].join(".")}o.extend({isReady:false,readyList:[],ready:function(){if(!o.isReady){o.isReady=true;if(o.readyList){o.each(o.readyList,function(){this.call(document,o)});o.readyList=null}o(document).triggerHandler("ready")}}});var x=false;function B(){if(x){return}x=true;if(document.addEventListener){document.addEventListener("DOMContentLoaded",function(){document.removeEventListener("DOMContentLoaded",arguments.callee,false);o.ready()},false)}else{if(document.attachEvent){document.attachEvent("onreadystatechange",function(){if(document.readyState==="complete"){document.detachEvent("onreadystatechange",arguments.callee);o.ready()}});if(document.documentElement.doScroll&&l==l.top){(function(){if(o.isReady){return}try{document.documentElement.doScroll("left")}catch(E){setTimeout(arguments.callee,0);return}o.ready()})()}}}o.event.add(l,"load",o.ready)}o.each(("blur,focus,load,resize,scroll,unload,click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave,change,select,submit,keydown,keypress,keyup,error").split(","),function(F,E){o.fn[E]=function(G){return G?this.bind(E,G):this.trigger(E)}});o(l).bind("unload",function(){for(var E in o.cache){if(E!=1&&o.cache[E].handle){o.event.remove(o.cache[E].handle.elem)}}});(function(){o.support={};var F=document.documentElement,G=document.createElement("script"),K=document.createElement("div"),J="script"+(new Date).getTime();K.style.display="none";K.innerHTML='   <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';var H=K.getElementsByTagName("*"),E=K.getElementsByTagName("a")[0];if(!H||!H.length||!E){return}o.support={leadingWhitespace:K.firstChild.nodeType==3,tbody:!K.getElementsByTagName("tbody").length,objectAll:!!K.getElementsByTagName("object")[0].getElementsByTagName("*").length,htmlSerialize:!!K.getElementsByTagName("link").length,style:/red/.test(E.getAttribute("style")),hrefNormalized:E.getAttribute("href")==="/a",opacity:E.style.opacity==="0.5",cssFloat:!!E.style.cssFloat,scriptEval:false,noCloneEvent:true,boxModel:null};G.type="text/javascript";try{G.appendChild(document.createTextNode("window."+J+"=1;"))}catch(I){}F.insertBefore(G,F.firstChild);if(l[J]){o.support.scriptEval=true;delete l[J]}F.removeChild(G);if(K.attachEvent&&K.fireEvent){K.attachEvent("onclick",function(){o.support.noCloneEvent=false;K.detachEvent("onclick",arguments.callee)});K.cloneNode(true).fireEvent("onclick")}o(function(){var L=document.createElement("div");L.style.width=L.style.paddingLeft="1px";document.body.appendChild(L);o.boxModel=o.support.boxModel=L.offsetWidth===2;document.body.removeChild(L).style.display="none"})})();var w=o.support.cssFloat?"cssFloat":"styleFloat";o.props={"for":"htmlFor","class":"className","float":w,cssFloat:w,styleFloat:w,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",tabindex:"tabIndex"};o.fn.extend({_load:o.fn.load,load:function(G,J,K){if(typeof G!=="string"){return this._load(G)}var I=G.indexOf(" ");if(I>=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("<div/>").append(M.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H<F;H++){var E=o.data(this[H],"olddisplay");this[H].style.display=E||"";if(o.css(this[H],"display")==="none"){var G=this[H].tagName,K;if(m[G]){K=m[G]}else{var I=o("<"+G+" />").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H<F;H++){this[H].style.display=o.data(this[H],"olddisplay")||""}return this}},hide:function(H,I){if(H){return this.animate(t("hide",3),H,I)}else{for(var G=0,F=this.length;G<F;G++){var E=o.data(this[G],"olddisplay");if(!E&&E!=="none"){o.data(this[G],"olddisplay",o.css(this[G],"display"))}}for(var G=0,F=this.length;G<F;G++){this[G].style.display="none"}return this}},_toggle:o.fn.toggle,toggle:function(G,F){var E=typeof G==="boolean";return o.isFunction(G)&&o.isFunction(F)?this._toggle.apply(this,arguments):G==null||E?this.each(function(){var H=E?G:o(this).is(":hidden");o(this)[H?"show":"hide"]()}):this.animate(t("toggle",3),G,F)},fadeTo:function(E,G,F){return this.animate({opacity:G},E,F)},animate:function(I,F,H,G){var E=o.speed(F,H,G);return this[E.queue===false?"each":"queue"](function(){var K=o.extend({},E),M,L=this.nodeType==1&&o(this).is(":hidden"),J=this;for(M in I){if(I[M]=="hide"&&L||I[M]=="show"&&!L){return K.complete.call(this)}if((M=="height"||M=="width")&&this.style){K.display=o.css(this,"display");K.overflow=this.style.overflow}}if(K.overflow!=null){this.style.overflow="hidden"}K.curAnim=o.extend({},I);o.each(I,function(O,S){var R=new o.fx(J,K,O);if(/toggle|show|hide/.test(S)){R[S=="toggle"?L?"show":"hide":S](I)}else{var Q=S.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),T=R.cur(true)||0;if(Q){var N=parseFloat(Q[2]),P=Q[3]||"px";if(P!="px"){J.style[O]=(N||1)+P;T=((N||1)/R.cur(true))*T;J.style[O]=T+P}if(Q[1]){N=((Q[1]=="-="?-1:1)*N)+T}R.custom(T,N,P)}else{R.custom(T,S,"")}}});return true})},stop:function(F,E){var G=o.timers;if(F){this.queue([])}this.each(function(){for(var H=G.length-1;H>=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J<K.length;J++){if(!K[J]()){K.splice(J--,1)}}if(!K.length){clearInterval(n);n=g}},13)}},show:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.show=true;this.custom(this.prop=="width"||this.prop=="height"?1:0,this.cur());o(this.elem).show()},hide:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(H){var G=e();if(H||G>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})();
/*
 * jQuery UI 1.7.2
 *
 * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI
 */
jQuery.ui||(function(c){var i=c.fn.remove,d=c.browser.mozilla&&(parseFloat(c.browser.version)<1.9);c.ui={version:"1.7.2",plugin:{add:function(k,l,n){var m=c.ui[k].prototype;for(var j in n){m.plugins[j]=m.plugins[j]||[];m.plugins[j].push([l,n[j]])}},call:function(j,l,k){var n=j.plugins[l];if(!n||!j.element[0].parentNode){return}for(var m=0;m<n.length;m++){if(j.options[n[m][0]]){n[m][1].apply(j.element,k)}}}},contains:function(k,j){return document.compareDocumentPosition?k.compareDocumentPosition(j)&16:k!==j&&k.contains(j)},hasScroll:function(m,k){if(c(m).css("overflow")=="hidden"){return false}var j=(k&&k=="left")?"scrollLeft":"scrollTop",l=false;if(m[j]>0){return true}m[j]=1;l=(m[j]>0);m[j]=0;return l},isOverAxis:function(k,j,l){return(k>j)&&(k<(j+l))},isOver:function(o,k,n,m,j,l){return c.ui.isOverAxis(o,n,j)&&c.ui.isOverAxis(k,m,l)},keyCode:{BACKSPACE:8,CAPS_LOCK:20,COMMA:188,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38}};if(d){var f=c.attr,e=c.fn.removeAttr,h="http://www.w3.org/2005/07/aaa",a=/^aria-/,b=/^wairole:/;c.attr=function(k,j,l){var m=l!==undefined;return(j=="role"?(m?f.call(this,k,j,"wairole:"+l):(f.apply(this,arguments)||"").replace(b,"")):(a.test(j)?(m?k.setAttributeNS(h,j.replace(a,"aaa:"),l):f.call(this,k,j.replace(a,"aaa:"))):f.apply(this,arguments)))};c.fn.removeAttr=function(j){return(a.test(j)?this.each(function(){this.removeAttributeNS(h,j.replace(a,""))}):e.call(this,j))}}c.fn.extend({remove:function(){c("*",this).add(this).each(function(){c(this).triggerHandler("remove")});return i.apply(this,arguments)},enableSelection:function(){return this.attr("unselectable","off").css("MozUserSelect","").unbind("selectstart.ui")},disableSelection:function(){return this.attr("unselectable","on").css("MozUserSelect","none").bind("selectstart.ui",function(){return false})},scrollParent:function(){var j;if((c.browser.msie&&(/(static|relative)/).test(this.css("position")))||(/absolute/).test(this.css("position"))){j=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test(c.curCSS(this,"position",1))&&(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}else{j=this.parents().filter(function(){return(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}return(/fixed/).test(this.css("position"))||!j.length?c(document):j}});c.extend(c.expr[":"],{data:function(l,k,j){return !!c.data(l,j[3])},focusable:function(k){var l=k.nodeName.toLowerCase(),j=c.attr(k,"tabindex");return(/input|select|textarea|button|object/.test(l)?!k.disabled:"a"==l||"area"==l?k.href||!isNaN(j):!isNaN(j))&&!c(k)["area"==l?"parents":"closest"](":hidden").length},tabbable:function(k){var j=c.attr(k,"tabindex");return(isNaN(j)||j>=0)&&c(k).is(":focusable")}});function g(m,n,o,l){function k(q){var p=c[m][n][q]||[];return(typeof p=="string"?p.split(/,?\s+/):p)}var j=k("getter");if(l.length==1&&typeof l[0]=="string"){j=j.concat(k("getterSetter"))}return(c.inArray(o,j)!=-1)}c.widget=function(k,j){var l=k.split(".")[0];k=k.split(".")[1];c.fn[k]=function(p){var n=(typeof p=="string"),o=Array.prototype.slice.call(arguments,1);if(n&&p.substring(0,1)=="_"){return this}if(n&&g(l,k,p,o)){var m=c.data(this[0],k);return(m?m[p].apply(m,o):undefined)}return this.each(function(){var q=c.data(this,k);(!q&&!n&&c.data(this,k,new c[l][k](this,p))._init());(q&&n&&c.isFunction(q[p])&&q[p].apply(q,o))})};c[l]=c[l]||{};c[l][k]=function(o,n){var m=this;this.namespace=l;this.widgetName=k;this.widgetEventPrefix=c[l][k].eventPrefix||k;this.widgetBaseClass=l+"-"+k;this.options=c.extend({},c.widget.defaults,c[l][k].defaults,c.metadata&&c.metadata.get(o)[k],n);this.element=c(o).bind("setData."+k,function(q,p,r){if(q.target==o){return m._setData(p,r)}}).bind("getData."+k,function(q,p){if(q.target==o){return m._getData(p)}}).bind("remove",function(){return m.destroy()})};c[l][k].prototype=c.extend({},c.widget.prototype,j);c[l][k].getterSetter="option"};c.widget.prototype={_init:function(){},destroy:function(){this.element.removeData(this.widgetName).removeClass(this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").removeAttr("aria-disabled")},option:function(l,m){var k=l,j=this;if(typeof l=="string"){if(m===undefined){return this._getData(l)}k={};k[l]=m}c.each(k,function(n,o){j._setData(n,o)})},_getData:function(j){return this.options[j]},_setData:function(j,k){this.options[j]=k;if(j=="disabled"){this.element[k?"addClass":"removeClass"](this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").attr("aria-disabled",k)}},enable:function(){this._setData("disabled",false)},disable:function(){this._setData("disabled",true)},_trigger:function(l,m,n){var p=this.options[l],j=(l==this.widgetEventPrefix?l:this.widgetEventPrefix+l);m=c.Event(m);m.type=j;if(m.originalEvent){for(var k=c.event.props.length,o;k;){o=c.event.props[--k];m[o]=m.originalEvent[o]}}this.element.trigger(m,n);return !(c.isFunction(p)&&p.call(this.element[0],m,n)===false||m.isDefaultPrevented())}};c.widget.defaults={disabled:false};c.ui.mouse={_mouseInit:function(){var j=this;this.element.bind("mousedown."+this.widgetName,function(k){return j._mouseDown(k)}).bind("click."+this.widgetName,function(k){if(j._preventClickEvent){j._preventClickEvent=false;k.stopImmediatePropagation();return false}});if(c.browser.msie){this._mouseUnselectable=this.element.attr("unselectable");this.element.attr("unselectable","on")}this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName);(c.browser.msie&&this.element.attr("unselectable",this._mouseUnselectable))},_mouseDown:function(l){l.originalEvent=l.originalEvent||{};if(l.originalEvent.mouseHandled){return}(this._mouseStarted&&this._mouseUp(l));this._mouseDownEvent=l;var k=this,m=(l.which==1),j=(typeof this.options.cancel=="string"?c(l.target).parents().add(l.target).filter(this.options.cancel).length:false);if(!m||j||!this._mouseCapture(l)){return true}this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){k.mouseDelayMet=true},this.options.delay)}if(this._mouseDistanceMet(l)&&this._mouseDelayMet(l)){this._mouseStarted=(this._mouseStart(l)!==false);if(!this._mouseStarted){l.preventDefault();return true}}this._mouseMoveDelegate=function(n){return k._mouseMove(n)};this._mouseUpDelegate=function(n){return k._mouseUp(n)};c(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);(c.browser.safari||l.preventDefault());l.originalEvent.mouseHandled=true;return true},_mouseMove:function(j){if(c.browser.msie&&!j.button){return this._mouseUp(j)}if(this._mouseStarted){this._mouseDrag(j);return j.preventDefault()}if(this._mouseDistanceMet(j)&&this._mouseDelayMet(j)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,j)!==false);(this._mouseStarted?this._mouseDrag(j):this._mouseUp(j))}return !this._mouseStarted},_mouseUp:function(j){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=(j.target==this._mouseDownEvent.target);this._mouseStop(j)}return false},_mouseDistanceMet:function(j){return(Math.max(Math.abs(this._mouseDownEvent.pageX-j.pageX),Math.abs(this._mouseDownEvent.pageY-j.pageY))>=this.options.distance)},_mouseDelayMet:function(j){return this.mouseDelayMet},_mouseStart:function(j){},_mouseDrag:function(j){},_mouseStop:function(j){},_mouseCapture:function(j){return true}};c.ui.mouse.defaults={cancel:null,distance:1,delay:0}})(jQuery);;/*
 * jQuery UI Draggable 1.7.2
 *
 * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI/Draggables
 *
 * Depends:
 *	ui.core.js
 */
(function(a){a.widget("ui.draggable",a.extend({},a.ui.mouse,{_init:function(){if(this.options.helper=="original"&&!(/^(?:r|a|f)/).test(this.element.css("position"))){this.element[0].style.position="relative"}(this.options.addClasses&&this.element.addClass("ui-draggable"));(this.options.disabled&&this.element.addClass("ui-draggable-disabled"));this._mouseInit()},destroy:function(){if(!this.element.data("draggable")){return}this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy()},_mouseCapture:function(b){var c=this.options;if(this.helper||c.disabled||a(b.target).is(".ui-resizable-handle")){return false}this.handle=this._getHandle(b);if(!this.handle){return false}return true},_mouseStart:function(b){var c=this.options;this.helper=this._createHelper(b);this._cacheHelperProportions();if(a.ui.ddmanager){a.ui.ddmanager.current=this}this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(b);this.originalPageX=b.pageX;this.originalPageY=b.pageY;if(c.cursorAt){this._adjustOffsetFromHelper(c.cursorAt)}if(c.containment){this._setContainment()}this._trigger("start",b);this._cacheHelperProportions();if(a.ui.ddmanager&&!c.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,b)}this.helper.addClass("ui-draggable-dragging");this._mouseDrag(b,true);return true},_mouseDrag:function(b,d){this.position=this._generatePosition(b);this.positionAbs=this._convertPositionTo("absolute");if(!d){var c=this._uiHash();this._trigger("drag",b,c);this.position=c.position}if(!this.options.axis||this.options.axis!="y"){this.helper[0].style.left=this.position.left+"px"}if(!this.options.axis||this.options.axis!="x"){this.helper[0].style.top=this.position.top+"px"}if(a.ui.ddmanager){a.ui.ddmanager.drag(this,b)}return false},_mouseStop:function(c){var d=false;if(a.ui.ddmanager&&!this.options.dropBehaviour){d=a.ui.ddmanager.drop(this,c)}if(this.dropped){d=this.dropped;this.dropped=false}if((this.options.revert=="invalid"&&!d)||(this.options.revert=="valid"&&d)||this.options.revert===true||(a.isFunction(this.options.revert)&&this.options.revert.call(this.element,d))){var b=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){b._trigger("stop",c);b._clear()})}else{this._trigger("stop",c);this._clear()}return false},_getHandle:function(b){var c=!this.options.handle||!a(this.options.handle,this.element).length?true:false;a(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==b.target){c=true}});return c},_createHelper:function(c){var d=this.options;var b=a.isFunction(d.helper)?a(d.helper.apply(this.element[0],[c])):(d.helper=="clone"?this.element.clone():this.element);if(!b.parents("body").length){b.appendTo((d.appendTo=="parent"?this.element[0].parentNode:d.appendTo))}if(b[0]!=this.element[0]&&!(/(fixed|absolute)/).test(b.css("position"))){b.css("position","absolute")}return b},_adjustOffsetFromHelper:function(b){if(b.left!=undefined){this.offset.click.left=b.left+this.margins.left}if(b.right!=undefined){this.offset.click.left=this.helperProportions.width-b.right+this.margins.left}if(b.top!=undefined){this.offset.click.top=b.top+this.margins.top}if(b.bottom!=undefined){this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top}},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])){b.left+=this.scrollParent.scrollLeft();b.top+=this.scrollParent.scrollTop()}if((this.offsetParent[0]==document.body)||(this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)){b={top:0,left:0}}return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var b=this.element.position();return{top:b.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:b.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else{return{top:0,left:0}}},_cacheMargins:function(){this.margins={left:(parseInt(this.element.css("marginLeft"),10)||0),top:(parseInt(this.element.css("marginTop"),10)||0)}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e=this.options;if(e.containment=="parent"){e.containment=this.helper[0].parentNode}if(e.containment=="document"||e.containment=="window"){this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,a(e.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a(e.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]}if(!(/^(document|window|parent)$/).test(e.containment)&&e.containment.constructor!=Array){var c=a(e.containment)[0];if(!c){return}var d=a(e.containment).offset();var b=(a(c).css("overflow")!="hidden");this.containment=[d.left+(parseInt(a(c).css("borderLeftWidth"),10)||0)+(parseInt(a(c).css("paddingLeft"),10)||0)-this.margins.left,d.top+(parseInt(a(c).css("borderTopWidth"),10)||0)+(parseInt(a(c).css("paddingTop"),10)||0)-this.margins.top,d.left+(b?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css("borderLeftWidth"),10)||0)-(parseInt(a(c).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,d.top+(b?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css("borderTopWidth"),10)||0)-(parseInt(a(c).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}else{if(e.containment.constructor==Array){this.containment=e.containment}}},_convertPositionTo:function(f,h){if(!h){h=this.position}var c=f=="absolute"?1:-1;var e=this.options,b=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=(/(html|body)/i).test(b[0].tagName);return{top:(h.top+this.offset.relative.top*c+this.offset.parent.top*c-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():(g?0:b.scrollTop()))*c)),left:(h.left+this.offset.relative.left*c+this.offset.parent.left*c-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:b.scrollLeft())*c))}},_generatePosition:function(e){var h=this.options,b=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,i=(/(html|body)/i).test(b[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0])){this.offset.relative=this._getRelativeOffset()}var d=e.pageX;var c=e.pageY;if(this.originalPosition){if(this.containment){if(e.pageX-this.offset.click.left<this.containment[0]){d=this.containment[0]+this.offset.click.left}if(e.pageY-this.offset.click.top<this.containment[1]){c=this.containment[1]+this.offset.click.top}if(e.pageX-this.offset.click.left>this.containment[2]){d=this.containment[2]+this.offset.click.left}if(e.pageY-this.offset.click.top>this.containment[3]){c=this.containment[3]+this.offset.click.top}}if(h.grid){var g=this.originalPageY+Math.round((c-this.originalPageY)/h.grid[1])*h.grid[1];c=this.containment?(!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:(!(g-this.offset.click.top<this.containment[1])?g-h.grid[1]:g+h.grid[1])):g;var f=this.originalPageX+Math.round((d-this.originalPageX)/h.grid[0])*h.grid[0];d=this.containment?(!(f-this.offset.click.left<this.containment[0]||f-this.offset.click.left>this.containment[2])?f:(!(f-this.offset.click.left<this.containment[0])?f-h.grid[0]:f+h.grid[0])):f}}return{top:(c-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():(i?0:b.scrollTop())))),left:(d-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():i?0:b.scrollLeft())))}},_clear:function(){this.helper.removeClass("ui-draggable-dragging");if(this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval){this.helper.remove()}this.helper=null;this.cancelHelperRemoval=false},_trigger:function(b,c,d){d=d||this._uiHash();a.ui.plugin.call(this,b,[c,d]);if(b=="drag"){this.positionAbs=this._convertPositionTo("absolute")}return a.widget.prototype._trigger.call(this,b,c,d)},plugins:{},_uiHash:function(b){return{helper:this.helper,position:this.position,absolutePosition:this.positionAbs,offset:this.positionAbs}}}));a.extend(a.ui.draggable,{version:"1.7.2",eventPrefix:"drag",defaults:{addClasses:true,appendTo:"parent",axis:false,cancel:":input,option",connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,delay:0,distance:1,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false}});a.ui.plugin.add("draggable","connectToSortable",{start:function(c,e){var d=a(this).data("draggable"),f=d.options,b=a.extend({},e,{item:d.element});d.sortables=[];a(f.connectToSortable).each(function(){var g=a.data(this,"sortable");if(g&&!g.options.disabled){d.sortables.push({instance:g,shouldRevert:g.options.revert});g._refreshItems();g._trigger("activate",c,b)}})},stop:function(c,e){var d=a(this).data("draggable"),b=a.extend({},e,{item:d.element});a.each(d.sortables,function(){if(this.instance.isOver){this.instance.isOver=0;d.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=false;if(this.shouldRevert){this.instance.options.revert=true}this.instance._mouseStop(c);this.instance.options.helper=this.instance.options._helper;if(d.options.helper=="original"){this.instance.currentItem.css({top:"auto",left:"auto"})}}else{this.instance.cancelHelperRemoval=false;this.instance._trigger("deactivate",c,b)}})},drag:function(c,f){var e=a(this).data("draggable"),b=this;var d=function(i){var n=this.offset.click.top,m=this.offset.click.left;var g=this.positionAbs.top,k=this.positionAbs.left;var j=i.height,l=i.width;var p=i.top,h=i.left;return a.ui.isOver(g+n,k+m,p,h,j,l)};a.each(e.sortables,function(g){this.instance.positionAbs=e.positionAbs;this.instance.helperProportions=e.helperProportions;this.instance.offset.click=e.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){if(!this.instance.isOver){this.instance.isOver=1;this.instance.currentItem=a(b).clone().appendTo(this.instance.element).data("sortable-item",true);this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return f.helper[0]};c.target=this.instance.currentItem[0];this.instance._mouseCapture(c,true);this.instance._mouseStart(c,true,true);this.instance.offset.click.top=e.offset.click.top;this.instance.offset.click.left=e.offset.click.left;this.instance.offset.parent.left-=e.offset.parent.left-this.instance.offset.parent.left;this.instance.offset.parent.top-=e.offset.parent.top-this.instance.offset.parent.top;e._trigger("toSortable",c);e.dropped=this.instance.element;e.currentItem=e.element;this.instance.fromOutside=e}if(this.instance.currentItem){this.instance._mouseDrag(c)}}else{if(this.instance.isOver){this.instance.isOver=0;this.instance.cancelHelperRemoval=true;this.instance.options.revert=false;this.instance._trigger("out",c,this.instance._uiHash(this.instance));this.instance._mouseStop(c,true);this.instance.options.helper=this.instance.options._helper;this.instance.currentItem.remove();if(this.instance.placeholder){this.instance.placeholder.remove()}e._trigger("fromSortable",c);e.dropped=false}}})}});a.ui.plugin.add("draggable","cursor",{start:function(c,d){var b=a("body"),e=a(this).data("draggable").options;if(b.css("cursor")){e._cursor=b.css("cursor")}b.css("cursor",e.cursor)},stop:function(b,c){var d=a(this).data("draggable").options;if(d._cursor){a("body").css("cursor",d._cursor)}}});a.ui.plugin.add("draggable","iframeFix",{start:function(b,c){var d=a(this).data("draggable").options;a(d.iframeFix===true?"iframe":d.iframeFix).each(function(){a('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1000}).css(a(this).offset()).appendTo("body")})},stop:function(b,c){a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)})}});a.ui.plugin.add("draggable","opacity",{start:function(c,d){var b=a(d.helper),e=a(this).data("draggable").options;if(b.css("opacity")){e._opacity=b.css("opacity")}b.css("opacity",e.opacity)},stop:function(b,c){var d=a(this).data("draggable").options;if(d._opacity){a(c.helper).css("opacity",d._opacity)}}});a.ui.plugin.add("draggable","scroll",{start:function(c,d){var b=a(this).data("draggable");if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!="HTML"){b.overflowOffset=b.scrollParent.offset()}},drag:function(d,e){var c=a(this).data("draggable"),f=c.options,b=false;if(c.scrollParent[0]!=document&&c.scrollParent[0].tagName!="HTML"){if(!f.axis||f.axis!="x"){if((c.overflowOffset.top+c.scrollParent[0].offsetHeight)-d.pageY<f.scrollSensitivity){c.scrollParent[0].scrollTop=b=c.scrollParent[0].scrollTop+f.scrollSpeed}else{if(d.pageY-c.overflowOffset.top<f.scrollSensitivity){c.scrollParent[0].scrollTop=b=c.scrollParent[0].scrollTop-f.scrollSpeed}}}if(!f.axis||f.axis!="y"){if((c.overflowOffset.left+c.scrollParent[0].offsetWidth)-d.pageX<f.scrollSensitivity){c.scrollParent[0].scrollLeft=b=c.scrollParent[0].scrollLeft+f.scrollSpeed}else{if(d.pageX-c.overflowOffset.left<f.scrollSensitivity){c.scrollParent[0].scrollLeft=b=c.scrollParent[0].scrollLeft-f.scrollSpeed}}}}else{if(!f.axis||f.axis!="x"){if(d.pageY-a(document).scrollTop()<f.scrollSensitivity){b=a(document).scrollTop(a(document).scrollTop()-f.scrollSpeed)}else{if(a(window).height()-(d.pageY-a(document).scrollTop())<f.scrollSensitivity){b=a(document).scrollTop(a(document).scrollTop()+f.scrollSpeed)}}}if(!f.axis||f.axis!="y"){if(d.pageX-a(document).scrollLeft()<f.scrollSensitivity){b=a(document).scrollLeft(a(document).scrollLeft()-f.scrollSpeed)}else{if(a(window).width()-(d.pageX-a(document).scrollLeft())<f.scrollSensitivity){b=a(document).scrollLeft(a(document).scrollLeft()+f.scrollSpeed)}}}}if(b!==false&&a.ui.ddmanager&&!f.dropBehaviour){a.ui.ddmanager.prepareOffsets(c,d)}}});a.ui.plugin.add("draggable","snap",{start:function(c,d){var b=a(this).data("draggable"),e=b.options;b.snapElements=[];a(e.snap.constructor!=String?(e.snap.items||":data(draggable)"):e.snap).each(function(){var g=a(this);var f=g.offset();if(this!=b.element[0]){b.snapElements.push({item:this,width:g.outerWidth(),height:g.outerHeight(),top:f.top,left:f.left})}})},drag:function(u,p){var g=a(this).data("draggable"),q=g.options;var y=q.snapTolerance;var x=p.offset.left,w=x+g.helperProportions.width,f=p.offset.top,e=f+g.helperProportions.height;for(var v=g.snapElements.length-1;v>=0;v--){var s=g.snapElements[v].left,n=s+g.snapElements[v].width,m=g.snapElements[v].top,A=m+g.snapElements[v].height;if(!((s-y<x&&x<n+y&&m-y<f&&f<A+y)||(s-y<x&&x<n+y&&m-y<e&&e<A+y)||(s-y<w&&w<n+y&&m-y<f&&f<A+y)||(s-y<w&&w<n+y&&m-y<e&&e<A+y))){if(g.snapElements[v].snapping){(g.options.snap.release&&g.options.snap.release.call(g.element,u,a.extend(g._uiHash(),{snapItem:g.snapElements[v].item})))}g.snapElements[v].snapping=false;continue}if(q.snapMode!="inner"){var c=Math.abs(m-e)<=y;var z=Math.abs(A-f)<=y;var j=Math.abs(s-w)<=y;var k=Math.abs(n-x)<=y;if(c){p.position.top=g._convertPositionTo("relative",{top:m-g.helperProportions.height,left:0}).top-g.margins.top}if(z){p.position.top=g._convertPositionTo("relative",{top:A,left:0}).top-g.margins.top}if(j){p.position.left=g._convertPositionTo("relative",{top:0,left:s-g.helperProportions.width}).left-g.margins.left}if(k){p.position.left=g._convertPositionTo("relative",{top:0,left:n}).left-g.margins.left}}var h=(c||z||j||k);if(q.snapMode!="outer"){var c=Math.abs(m-f)<=y;var z=Math.abs(A-e)<=y;var j=Math.abs(s-x)<=y;var k=Math.abs(n-w)<=y;if(c){p.position.top=g._convertPositionTo("relative",{top:m,left:0}).top-g.margins.top}if(z){p.position.top=g._convertPositionTo("relative",{top:A-g.helperProportions.height,left:0}).top-g.margins.top}if(j){p.position.left=g._convertPositionTo("relative",{top:0,left:s}).left-g.margins.left}if(k){p.position.left=g._convertPositionTo("relative",{top:0,left:n-g.helperProportions.width}).left-g.margins.left}}if(!g.snapElements[v].snapping&&(c||z||j||k||h)){(g.options.snap.snap&&g.options.snap.snap.call(g.element,u,a.extend(g._uiHash(),{snapItem:g.snapElements[v].item})))}g.snapElements[v].snapping=(c||z||j||k||h)}}});a.ui.plugin.add("draggable","stack",{start:function(b,c){var e=a(this).data("draggable").options;var d=a.makeArray(a(e.stack.group)).sort(function(g,f){return(parseInt(a(g).css("zIndex"),10)||e.stack.min)-(parseInt(a(f).css("zIndex"),10)||e.stack.min)});a(d).each(function(f){this.style.zIndex=e.stack.min+f});this[0].style.zIndex=e.stack.min+d.length}});a.ui.plugin.add("draggable","zIndex",{start:function(c,d){var b=a(d.helper),e=a(this).data("draggable").options;if(b.css("zIndex")){e._zIndex=b.css("zIndex")}b.css("zIndex",e.zIndex)},stop:function(b,c){var d=a(this).data("draggable").options;if(d._zIndex){a(c.helper).css("zIndex",d._zIndex)}}})})(jQuery);;/*
 * jQuery UI Droppable 1.7.2
 *
 * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI/Droppables
 *
 * Depends:
 *	ui.core.js
 *	ui.draggable.js
 */
(function(a){a.widget("ui.droppable",{_init:function(){var c=this.options,b=c.accept;this.isover=0;this.isout=1;this.options.accept=this.options.accept&&a.isFunction(this.options.accept)?this.options.accept:function(e){return e.is(b)};this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight};a.ui.ddmanager.droppables[this.options.scope]=a.ui.ddmanager.droppables[this.options.scope]||[];a.ui.ddmanager.droppables[this.options.scope].push(this);(this.options.addClasses&&this.element.addClass("ui-droppable"))},destroy:function(){var b=a.ui.ddmanager.droppables[this.options.scope];for(var c=0;c<b.length;c++){if(b[c]==this){b.splice(c,1)}}this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable")},_setData:function(b,c){if(b=="accept"){this.options.accept=c&&a.isFunction(c)?c:function(e){return e.is(c)}}else{a.widget.prototype._setData.apply(this,arguments)}},_activate:function(c){var b=a.ui.ddmanager.current;if(this.options.activeClass){this.element.addClass(this.options.activeClass)}(b&&this._trigger("activate",c,this.ui(b)))},_deactivate:function(c){var b=a.ui.ddmanager.current;if(this.options.activeClass){this.element.removeClass(this.options.activeClass)}(b&&this._trigger("deactivate",c,this.ui(b)))},_over:function(c){var b=a.ui.ddmanager.current;if(!b||(b.currentItem||b.element)[0]==this.element[0]){return}if(this.options.accept.call(this.element[0],(b.currentItem||b.element))){if(this.options.hoverClass){this.element.addClass(this.options.hoverClass)}this._trigger("over",c,this.ui(b))}},_out:function(c){var b=a.ui.ddmanager.current;if(!b||(b.currentItem||b.element)[0]==this.element[0]){return}if(this.options.accept.call(this.element[0],(b.currentItem||b.element))){if(this.options.hoverClass){this.element.removeClass(this.options.hoverClass)}this._trigger("out",c,this.ui(b))}},_drop:function(c,d){var b=d||a.ui.ddmanager.current;if(!b||(b.currentItem||b.element)[0]==this.element[0]){return false}var e=false;this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var f=a.data(this,"droppable");if(f.options.greedy&&a.ui.intersect(b,a.extend(f,{offset:f.element.offset()}),f.options.tolerance)){e=true;return false}});if(e){return false}if(this.options.accept.call(this.element[0],(b.currentItem||b.element))){if(this.options.activeClass){this.element.removeClass(this.options.activeClass)}if(this.options.hoverClass){this.element.removeClass(this.options.hoverClass)}this._trigger("drop",c,this.ui(b));return this.element}return false},ui:function(b){return{draggable:(b.currentItem||b.element),helper:b.helper,position:b.position,absolutePosition:b.positionAbs,offset:b.positionAbs}}});a.extend(a.ui.droppable,{version:"1.7.2",eventPrefix:"drop",defaults:{accept:"*",activeClass:false,addClasses:true,greedy:false,hoverClass:false,scope:"default",tolerance:"intersect"}});a.ui.intersect=function(q,j,o){if(!j.offset){return false}var e=(q.positionAbs||q.position.absolute).left,d=e+q.helperProportions.width,n=(q.positionAbs||q.position.absolute).top,m=n+q.helperProportions.height;var g=j.offset.left,c=g+j.proportions.width,p=j.offset.top,k=p+j.proportions.height;switch(o){case"fit":return(g<e&&d<c&&p<n&&m<k);break;case"intersect":return(g<e+(q.helperProportions.width/2)&&d-(q.helperProportions.width/2)<c&&p<n+(q.helperProportions.height/2)&&m-(q.helperProportions.height/2)<k);break;case"pointer":var h=((q.positionAbs||q.position.absolute).left+(q.clickOffset||q.offset.click).left),i=((q.positionAbs||q.position.absolute).top+(q.clickOffset||q.offset.click).top),f=a.ui.isOver(i,h,p,g,j.proportions.height,j.proportions.width);return f;break;case"touch":return((n>=p&&n<=k)||(m>=p&&m<=k)||(n<p&&m>k))&&((e>=g&&e<=c)||(d>=g&&d<=c)||(e<g&&d>c));break;default:return false;break}};a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(e,g){var b=a.ui.ddmanager.droppables[e.options.scope];var f=g?g.type:null;var h=(e.currentItem||e.element).find(":data(droppable)").andSelf();droppablesLoop:for(var d=0;d<b.length;d++){if(b[d].options.disabled||(e&&!b[d].options.accept.call(b[d].element[0],(e.currentItem||e.element)))){continue}for(var c=0;c<h.length;c++){if(h[c]==b[d].element[0]){b[d].proportions.height=0;continue droppablesLoop}}b[d].visible=b[d].element.css("display")!="none";if(!b[d].visible){continue}b[d].offset=b[d].element.offset();b[d].proportions={width:b[d].element[0].offsetWidth,height:b[d].element[0].offsetHeight};if(f=="mousedown"){b[d]._activate.call(b[d],g)}}},drop:function(b,c){var d=false;a.each(a.ui.ddmanager.droppables[b.options.scope],function(){if(!this.options){return}if(!this.options.disabled&&this.visible&&a.ui.intersect(b,this,this.options.tolerance)){d=this._drop.call(this,c)}if(!this.options.disabled&&this.visible&&this.options.accept.call(this.element[0],(b.currentItem||b.element))){this.isout=1;this.isover=0;this._deactivate.call(this,c)}});return d},drag:function(b,c){if(b.options.refreshPositions){a.ui.ddmanager.prepareOffsets(b,c)}a.each(a.ui.ddmanager.droppables[b.options.scope],function(){if(this.options.disabled||this.greedyChild||!this.visible){return}var e=a.ui.intersect(b,this,this.options.tolerance);var g=!e&&this.isover==1?"isout":(e&&this.isover==0?"isover":null);if(!g){return}var f;if(this.options.greedy){var d=this.element.parents(":data(droppable):eq(0)");if(d.length){f=a.data(d[0],"droppable");f.greedyChild=(g=="isover"?1:0)}}if(f&&g=="isover"){f.isover=0;f.isout=1;f._out.call(f,c)}this[g]=1;this[g=="isout"?"isover":"isout"]=0;this[g=="isover"?"_over":"_out"].call(this,c);if(f&&g=="isout"){f.isout=0;f.isover=1;f._over.call(f,c)}})}}})(jQuery);;/*
 * jQuery UI Resizable 1.7.2
 *
 * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI/Resizables
 *
 * Depends:
 *	ui.core.js
 */
(function(c){c.widget("ui.resizable",c.extend({},c.ui.mouse,{_init:function(){var e=this,j=this.options;this.element.addClass("ui-resizable");c.extend(this,{_aspectRatio:!!(j.aspectRatio),aspectRatio:j.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:j.helper||j.ghost||j.animate?j.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){if(/relative/.test(this.element.css("position"))&&c.browser.opera){this.element.css({position:"relative",top:"auto",left:"auto"})}this.element.wrap(c('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=j.handles||(!c(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all"){this.handles="n,e,s,w,se,sw,ne,nw"}var k=this.handles.split(",");this.handles={};for(var f=0;f<k.length;f++){var h=c.trim(k[f]),d="ui-resizable-"+h;var g=c('<div class="ui-resizable-handle '+d+'"></div>');if(/sw|se|ne|nw/.test(h)){g.css({zIndex:++j.zIndex})}if("se"==h){g.addClass("ui-icon ui-icon-gripsmall-diagonal-se")}this.handles[h]=".ui-resizable-"+h;this.element.append(g)}}this._renderAxis=function(p){p=p||this.element;for(var m in this.handles){if(this.handles[m].constructor==String){this.handles[m]=c(this.handles[m],this.element).show()}if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var n=c(this.handles[m],this.element),o=0;o=/sw|ne|nw|se|n|s/.test(m)?n.outerHeight():n.outerWidth();var l=["padding",/ne|nw|n/.test(m)?"Top":/se|sw|s/.test(m)?"Bottom":/^e$/.test(m)?"Right":"Left"].join("");p.css(l,o);this._proportionallyResize()}if(!c(this.handles[m]).length){continue}}};this._renderAxis(this.element);this._handles=c(".ui-resizable-handle",this.element).disableSelection();this._handles.mouseover(function(){if(!e.resizing){if(this.className){var i=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)}e.axis=i&&i[1]?i[1]:"se"}});if(j.autoHide){this._handles.hide();c(this.element).addClass("ui-resizable-autohide").hover(function(){c(this).removeClass("ui-resizable-autohide");e._handles.show()},function(){if(!e.resizing){c(this).addClass("ui-resizable-autohide");e._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var d=function(f){c(f).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){d(this.element);var e=this.element;e.parent().append(this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")})).end().remove()}this.originalElement.css("resize",this.originalResizeStyle);d(this.originalElement)},_mouseCapture:function(e){var f=false;for(var d in this.handles){if(c(this.handles[d])[0]==e.target){f=true}}return this.options.disabled||!!f},_mouseStart:function(f){var i=this.options,e=this.element.position(),d=this.element;this.resizing=true;this.documentScroll={top:c(document).scrollTop(),left:c(document).scrollLeft()};if(d.is(".ui-draggable")||(/absolute/).test(d.css("position"))){d.css({position:"absolute",top:e.top,left:e.left})}if(c.browser.opera&&(/relative/).test(d.css("position"))){d.css({position:"relative",top:"auto",left:"auto"})}this._renderProxy();var j=b(this.helper.css("left")),g=b(this.helper.css("top"));if(i.containment){j+=c(i.containment).scrollLeft()||0;g+=c(i.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:j,top:g};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:j,top:g};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:f.pageX,top:f.pageY};this.aspectRatio=(typeof i.aspectRatio=="number")?i.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);var h=c(".ui-resizable-"+this.axis).css("cursor");c("body").css("cursor",h=="auto"?this.axis+"-resize":h);d.addClass("ui-resizable-resizing");this._propagate("start",f);return true},_mouseDrag:function(d){var g=this.helper,f=this.options,l={},p=this,i=this.originalMousePosition,m=this.axis;var q=(d.pageX-i.left)||0,n=(d.pageY-i.top)||0;var h=this._change[m];if(!h){return false}var k=h.apply(this,[d,q,n]),j=c.browser.msie&&c.browser.version<7,e=this.sizeDiff;if(this._aspectRatio||d.shiftKey){k=this._updateRatio(k,d)}k=this._respectSize(k,d);this._propagate("resize",d);g.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});if(!this._helper&&this._proportionallyResizeElements.length){this._proportionallyResize()}this._updateCache(k);this._trigger("resize",d,this.ui());return false},_mouseStop:function(g){this.resizing=false;var h=this.options,l=this;if(this._helper){var f=this._proportionallyResizeElements,d=f.length&&(/textarea/i).test(f[0].nodeName),e=d&&c.ui.hasScroll(f[0],"left")?0:l.sizeDiff.height,j=d?0:l.sizeDiff.width;var m={width:(l.size.width-j),height:(l.size.height-e)},i=(parseInt(l.element.css("left"),10)+(l.position.left-l.originalPosition.left))||null,k=(parseInt(l.element.css("top"),10)+(l.position.top-l.originalPosition.top))||null;if(!h.animate){this.element.css(c.extend(m,{top:k,left:i}))}l.helper.height(l.size.height);l.helper.width(l.size.width);if(this._helper&&!h.animate){this._proportionallyResize()}}c("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",g);if(this._helper){this.helper.remove()}return false},_updateCache:function(d){var e=this.options;this.offset=this.helper.offset();if(a(d.left)){this.position.left=d.left}if(a(d.top)){this.position.top=d.top}if(a(d.height)){this.size.height=d.height}if(a(d.width)){this.size.width=d.width}},_updateRatio:function(g,f){var h=this.options,i=this.position,e=this.size,d=this.axis;if(g.height){g.width=(e.height*this.aspectRatio)}else{if(g.width){g.height=(e.width/this.aspectRatio)}}if(d=="sw"){g.left=i.left+(e.width-g.width);g.top=null}if(d=="nw"){g.top=i.top+(e.height-g.height);g.left=i.left+(e.width-g.width)}return g},_respectSize:function(k,f){var i=this.helper,h=this.options,q=this._aspectRatio||f.shiftKey,p=this.axis,s=a(k.width)&&h.maxWidth&&(h.maxWidth<k.width),l=a(k.height)&&h.maxHeight&&(h.maxHeight<k.height),g=a(k.width)&&h.minWidth&&(h.minWidth>k.width),r=a(k.height)&&h.minHeight&&(h.minHeight>k.height);if(g){k.width=h.minWidth}if(r){k.height=h.minHeight}if(s){k.width=h.maxWidth}if(l){k.height=h.maxHeight}var e=this.originalPosition.left+this.originalSize.width,n=this.position.top+this.size.height;var j=/sw|nw|w/.test(p),d=/nw|ne|n/.test(p);if(g&&j){k.left=e-h.minWidth}if(s&&j){k.left=e-h.maxWidth}if(r&&d){k.top=n-h.minHeight}if(l&&d){k.top=n-h.maxHeight}var m=!k.width&&!k.height;if(m&&!k.left&&k.top){k.top=null}else{if(m&&!k.top&&k.left){k.left=null}}return k},_proportionallyResize:function(){var j=this.options;if(!this._proportionallyResizeElements.length){return}var f=this.helper||this.element;for(var e=0;e<this._proportionallyResizeElements.length;e++){var g=this._proportionallyResizeElements[e];if(!this.borderDif){var d=[g.css("borderTopWidth"),g.css("borderRightWidth"),g.css("borderBottomWidth"),g.css("borderLeftWidth")],h=[g.css("paddingTop"),g.css("paddingRight"),g.css("paddingBottom"),g.css("paddingLeft")];this.borderDif=c.map(d,function(k,m){var l=parseInt(k,10)||0,n=parseInt(h[m],10)||0;return l+n})}if(c.browser.msie&&!(!(c(f).is(":hidden")||c(f).parents(":hidden").length))){continue}g.css({height:(f.height()-this.borderDif[0]-this.borderDif[2])||0,width:(f.width()-this.borderDif[1]-this.borderDif[3])||0})}},_renderProxy:function(){var e=this.element,h=this.options;this.elementOffset=e.offset();if(this._helper){this.helper=this.helper||c('<div style="overflow:hidden;"></div>');var d=c.browser.msie&&c.browser.version<7,f=(d?1:0),g=(d?2:-1);this.helper.addClass(this._helper).css({width:this.element.outerWidth()+g,height:this.element.outerHeight()+g,position:"absolute",left:this.elementOffset.left-f+"px",top:this.elementOffset.top-f+"px",zIndex:++h.zIndex});this.helper.appendTo("body").disableSelection()}else{this.helper=this.element}},_change:{e:function(f,e,d){return{width:this.originalSize.width+e}},w:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{left:h.left+e,width:f.width-e}},n:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{top:h.top+d,height:f.height-d}},s:function(f,e,d){return{height:this.originalSize.height+d}},se:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},sw:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[f,e,d]))},ne:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},nw:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[f,e,d]))}},_propagate:function(e,d){c.ui.plugin.call(this,e,[d,this.ui()]);(e!="resize"&&this._trigger(e,d,this.ui()))},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}));c.extend(c.ui.resizable,{version:"1.7.2",eventPrefix:"resize",defaults:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,cancel:":input,option",containment:false,delay:0,distance:1,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1000}});c.ui.plugin.add("resizable","alsoResize",{start:function(e,f){var d=c(this).data("resizable"),g=d.options;_store=function(h){c(h).each(function(){c(this).data("resizable-alsoresize",{width:parseInt(c(this).width(),10),height:parseInt(c(this).height(),10),left:parseInt(c(this).css("left"),10),top:parseInt(c(this).css("top"),10)})})};if(typeof(g.alsoResize)=="object"&&!g.alsoResize.parentNode){if(g.alsoResize.length){g.alsoResize=g.alsoResize[0];_store(g.alsoResize)}else{c.each(g.alsoResize,function(h,i){_store(h)})}}else{_store(g.alsoResize)}},resize:function(f,h){var e=c(this).data("resizable"),i=e.options,g=e.originalSize,k=e.originalPosition;var j={height:(e.size.height-g.height)||0,width:(e.size.width-g.width)||0,top:(e.position.top-k.top)||0,left:(e.position.left-k.left)||0},d=function(l,m){c(l).each(function(){var p=c(this),q=c(this).data("resizable-alsoresize"),o={},n=m&&m.length?m:["width","height","top","left"];c.each(n||["width","height","top","left"],function(r,t){var s=(q[t]||0)+(j[t]||0);if(s&&s>=0){o[t]=s||null}});if(/relative/.test(p.css("position"))&&c.browser.opera){e._revertToRelativePosition=true;p.css({position:"absolute",top:"auto",left:"auto"})}p.css(o)})};if(typeof(i.alsoResize)=="object"&&!i.alsoResize.nodeType){c.each(i.alsoResize,function(l,m){d(l,m)})}else{d(i.alsoResize)}},stop:function(e,f){var d=c(this).data("resizable");if(d._revertToRelativePosition&&c.browser.opera){d._revertToRelativePosition=false;el.css({position:"relative"})}c(this).removeData("resizable-alsoresize-start")}});c.ui.plugin.add("resizable","animate",{stop:function(h,m){var n=c(this).data("resizable"),i=n.options;var g=n._proportionallyResizeElements,d=g.length&&(/textarea/i).test(g[0].nodeName),e=d&&c.ui.hasScroll(g[0],"left")?0:n.sizeDiff.height,k=d?0:n.sizeDiff.width;var f={width:(n.size.width-k),height:(n.size.height-e)},j=(parseInt(n.element.css("left"),10)+(n.position.left-n.originalPosition.left))||null,l=(parseInt(n.element.css("top"),10)+(n.position.top-n.originalPosition.top))||null;n.element.animate(c.extend(f,l&&j?{top:l,left:j}:{}),{duration:i.animateDuration,easing:i.animateEasing,step:function(){var o={width:parseInt(n.element.css("width"),10),height:parseInt(n.element.css("height"),10),top:parseInt(n.element.css("top"),10),left:parseInt(n.element.css("left"),10)};if(g&&g.length){c(g[0]).css({width:o.width,height:o.height})}n._updateCache(o);n._propagate("resize",h)}})}});c.ui.plugin.add("resizable","containment",{start:function(e,q){var s=c(this).data("resizable"),i=s.options,k=s.element;var f=i.containment,j=(f instanceof c)?f.get(0):(/parent/.test(f))?k.parent().get(0):f;if(!j){return}s.containerElement=c(j);if(/document/.test(f)||f==document){s.containerOffset={left:0,top:0};s.containerPosition={left:0,top:0};s.parentData={element:c(document),left:0,top:0,width:c(document).width(),height:c(document).height()||document.body.parentNode.scrollHeight}}else{var m=c(j),h=[];c(["Top","Right","Left","Bottom"]).each(function(p,o){h[p]=b(m.css("padding"+o))});s.containerOffset=m.offset();s.containerPosition=m.position();s.containerSize={height:(m.innerHeight()-h[3]),width:(m.innerWidth()-h[1])};var n=s.containerOffset,d=s.containerSize.height,l=s.containerSize.width,g=(c.ui.hasScroll(j,"left")?j.scrollWidth:l),r=(c.ui.hasScroll(j)?j.scrollHeight:d);s.parentData={element:j,left:n.left,top:n.top,width:g,height:r}}},resize:function(f,p){var s=c(this).data("resizable"),h=s.options,e=s.containerSize,n=s.containerOffset,l=s.size,m=s.position,q=s._aspectRatio||f.shiftKey,d={top:0,left:0},g=s.containerElement;if(g[0]!=document&&(/static/).test(g.css("position"))){d=n}if(m.left<(s._helper?n.left:0)){s.size.width=s.size.width+(s._helper?(s.position.left-n.left):(s.position.left-d.left));if(q){s.size.height=s.size.width/h.aspectRatio}s.position.left=h.helper?n.left:0}if(m.top<(s._helper?n.top:0)){s.size.height=s.size.height+(s._helper?(s.position.top-n.top):s.position.top);if(q){s.size.width=s.size.height*h.aspectRatio}s.position.top=s._helper?n.top:0}s.offset.left=s.parentData.left+s.position.left;s.offset.top=s.parentData.top+s.position.top;var k=Math.abs((s._helper?s.offset.left-d.left:(s.offset.left-d.left))+s.sizeDiff.width),r=Math.abs((s._helper?s.offset.top-d.top:(s.offset.top-n.top))+s.sizeDiff.height);var j=s.containerElement.get(0)==s.element.parent().get(0),i=/relative|absolute/.test(s.containerElement.css("position"));if(j&&i){k-=s.parentData.left}if(k+s.size.width>=s.parentData.width){s.size.width=s.parentData.width-k;if(q){s.size.height=s.size.width/s.aspectRatio}}if(r+s.size.height>=s.parentData.height){s.size.height=s.parentData.height-r;if(q){s.size.width=s.size.height*s.aspectRatio}}},stop:function(e,m){var p=c(this).data("resizable"),f=p.options,k=p.position,l=p.containerOffset,d=p.containerPosition,g=p.containerElement;var i=c(p.helper),q=i.offset(),n=i.outerWidth()-p.sizeDiff.width,j=i.outerHeight()-p.sizeDiff.height;if(p._helper&&!f.animate&&(/relative/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}if(p._helper&&!f.animate&&(/static/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}}});c.ui.plugin.add("resizable","ghost",{start:function(f,g){var d=c(this).data("resizable"),h=d.options,e=d.size;d.ghost=d.originalElement.clone();d.ghost.css({opacity:0.25,display:"block",position:"relative",height:e.height,width:e.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof h.ghost=="string"?h.ghost:"");d.ghost.appendTo(d.helper)},resize:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost){d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})}},stop:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost&&d.helper){d.helper.get(0).removeChild(d.ghost.get(0))}}});c.ui.plugin.add("resizable","grid",{resize:function(d,l){var n=c(this).data("resizable"),g=n.options,j=n.size,h=n.originalSize,i=n.originalPosition,m=n.axis,k=g._aspectRatio||d.shiftKey;g.grid=typeof g.grid=="number"?[g.grid,g.grid]:g.grid;var f=Math.round((j.width-h.width)/(g.grid[0]||1))*(g.grid[0]||1),e=Math.round((j.height-h.height)/(g.grid[1]||1))*(g.grid[1]||1);if(/^(se|s|e)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e}else{if(/^(ne)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e}else{if(/^(sw)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.left=i.left-f}else{n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e;n.position.left=i.left-f}}}}});var b=function(d){return parseInt(d,10)||0};var a=function(d){return !isNaN(parseInt(d,10))}})(jQuery);;/*
 * jQuery UI Selectable 1.7.2
 *
 * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI/Selectables
 *
 * Depends:
 *	ui.core.js
 */
(function(a){a.widget("ui.selectable",a.extend({},a.ui.mouse,{_init:function(){var b=this;this.element.addClass("ui-selectable");this.dragged=false;var c;this.refresh=function(){c=a(b.options.filter,b.element[0]);c.each(function(){var d=a(this);var e=d.offset();a.data(this,"selectable-item",{element:this,$element:d,left:e.left,top:e.top,right:e.left+d.outerWidth(),bottom:e.top+d.outerHeight(),startselected:false,selected:d.hasClass("ui-selected"),selecting:d.hasClass("ui-selecting"),unselecting:d.hasClass("ui-unselecting")})})};this.refresh();this.selectees=c.addClass("ui-selectee");this._mouseInit();this.helper=a(document.createElement("div")).css({border:"1px dotted black"}).addClass("ui-selectable-helper")},destroy:function(){this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy()},_mouseStart:function(d){var b=this;this.opos=[d.pageX,d.pageY];if(this.options.disabled){return}var c=this.options;this.selectees=a(c.filter,this.element[0]);this._trigger("start",d);a(c.appendTo).append(this.helper);this.helper.css({"z-index":100,position:"absolute",left:d.clientX,top:d.clientY,width:0,height:0});if(c.autoRefresh){this.refresh()}this.selectees.filter(".ui-selected").each(function(){var e=a.data(this,"selectable-item");e.startselected=true;if(!d.metaKey){e.$element.removeClass("ui-selected");e.selected=false;e.$element.addClass("ui-unselecting");e.unselecting=true;b._trigger("unselecting",d,{unselecting:e.element})}});a(d.target).parents().andSelf().each(function(){var e=a.data(this,"selectable-item");if(e){e.$element.removeClass("ui-unselecting").addClass("ui-selecting");e.unselecting=false;e.selecting=true;e.selected=true;b._trigger("selecting",d,{selecting:e.element});return false}})},_mouseDrag:function(i){var c=this;this.dragged=true;if(this.options.disabled){return}var e=this.options;var d=this.opos[0],h=this.opos[1],b=i.pageX,g=i.pageY;if(d>b){var f=b;b=d;d=f}if(h>g){var f=g;g=h;h=f}this.helper.css({left:d,top:h,width:b-d,height:g-h});this.selectees.each(function(){var j=a.data(this,"selectable-item");if(!j||j.element==c.element[0]){return}var k=false;if(e.tolerance=="touch"){k=(!(j.left>b||j.right<d||j.top>g||j.bottom<h))}else{if(e.tolerance=="fit"){k=(j.left>d&&j.right<b&&j.top>h&&j.bottom<g)}}if(k){if(j.selected){j.$element.removeClass("ui-selected");j.selected=false}if(j.unselecting){j.$element.removeClass("ui-unselecting");j.unselecting=false}if(!j.selecting){j.$element.addClass("ui-selecting");j.selecting=true;c._trigger("selecting",i,{selecting:j.element})}}else{if(j.selecting){if(i.metaKey&&j.startselected){j.$element.removeClass("ui-selecting");j.selecting=false;j.$element.addClass("ui-selected");j.selected=true}else{j.$element.removeClass("ui-selecting");j.selecting=false;if(j.startselected){j.$element.addClass("ui-unselecting");j.unselecting=true}c._trigger("unselecting",i,{unselecting:j.element})}}if(j.selected){if(!i.metaKey&&!j.startselected){j.$element.removeClass("ui-selected");j.selected=false;j.$element.addClass("ui-unselecting");j.unselecting=true;c._trigger("unselecting",i,{unselecting:j.element})}}}});return false},_mouseStop:function(d){var b=this;this.dragged=false;var c=this.options;a(".ui-unselecting",this.element[0]).each(function(){var e=a.data(this,"selectable-item");e.$element.removeClass("ui-unselecting");e.unselecting=false;e.startselected=false;b._trigger("unselected",d,{unselected:e.element})});a(".ui-selecting",this.element[0]).each(function(){var e=a.data(this,"selectable-item");e.$element.removeClass("ui-selecting").addClass("ui-selected");e.selecting=false;e.selected=true;e.startselected=true;b._trigger("selected",d,{selected:e.element})});this._trigger("stop",d);this.helper.remove();return false}}));a.extend(a.ui.selectable,{version:"1.7.2",defaults:{appendTo:"body",autoRefresh:true,cancel:":input,option",delay:0,distance:0,filter:"*",tolerance:"touch"}})})(jQuery);;/*
 * jQuery UI Sortable 1.7.2
 *
 * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI/Sortables
 *
 * Depends:
 *	ui.core.js
 */
(function(a){a.widget("ui.sortable",a.extend({},a.ui.mouse,{_init:function(){var b=this.options;this.containerCache={};this.element.addClass("ui-sortable");this.refresh();this.floating=this.items.length?(/left|right/).test(this.items[0].item.css("float")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var b=this.items.length-1;b>=0;b--){this.items[b].item.removeData("sortable-item")}},_mouseCapture:function(e,f){if(this.reverting){return false}if(this.options.disabled||this.options.type=="static"){return false}this._refreshItems(e);var d=null,c=this,b=a(e.target).parents().each(function(){if(a.data(this,"sortable-item")==c){d=a(this);return false}});if(a.data(e.target,"sortable-item")==c){d=a(e.target)}if(!d){return false}if(this.options.handle&&!f){var g=false;a(this.options.handle,d).find("*").andSelf().each(function(){if(this==e.target){g=true}});if(!g){return false}}this.currentItem=d;this._removeCurrentsFromItems();return true},_mouseStart:function(e,f,b){var g=this.options,c=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(e);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");a.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(e);this.originalPageX=e.pageX;this.originalPageY=e.pageY;if(g.cursorAt){this._adjustOffsetFromHelper(g.cursorAt)}this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};if(this.helper[0]!=this.currentItem[0]){this.currentItem.hide()}this._createPlaceholder();if(g.containment){this._setContainment()}if(g.cursor){if(a("body").css("cursor")){this._storedCursor=a("body").css("cursor")}a("body").css("cursor",g.cursor)}if(g.opacity){if(this.helper.css("opacity")){this._storedOpacity=this.helper.css("opacity")}this.helper.css("opacity",g.opacity)}if(g.zIndex){if(this.helper.css("zIndex")){this._storedZIndex=this.helper.css("zIndex")}this.helper.css("zIndex",g.zIndex)}if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){this.overflowOffset=this.scrollParent.offset()}this._trigger("start",e,this._uiHash());if(!this._preserveHelperProportions){this._cacheHelperProportions()}if(!b){for(var d=this.containers.length-1;d>=0;d--){this.containers[d]._trigger("activate",e,c._uiHash(this))}}if(a.ui.ddmanager){a.ui.ddmanager.current=this}if(a.ui.ddmanager&&!g.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,e)}this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(e);return true},_mouseDrag:function(f){this.position=this._generatePosition(f);this.positionAbs=this._convertPositionTo("absolute");if(!this.lastPositionAbs){this.lastPositionAbs=this.positionAbs}if(this.options.scroll){var g=this.options,b=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if((this.overflowOffset.top+this.scrollParent[0].offsetHeight)-f.pageY<g.scrollSensitivity){this.scrollParent[0].scrollTop=b=this.scrollParent[0].scrollTop+g.scrollSpeed}else{if(f.pageY-this.overflowOffset.top<g.scrollSensitivity){this.scrollParent[0].scrollTop=b=this.scrollParent[0].scrollTop-g.scrollSpeed}}if((this.overflowOffset.left+this.scrollParent[0].offsetWidth)-f.pageX<g.scrollSensitivity){this.scrollParent[0].scrollLeft=b=this.scrollParent[0].scrollLeft+g.scrollSpeed}else{if(f.pageX-this.overflowOffset.left<g.scrollSensitivity){this.scrollParent[0].scrollLeft=b=this.scrollParent[0].scrollLeft-g.scrollSpeed}}}else{if(f.pageY-a(document).scrollTop()<g.scrollSensitivity){b=a(document).scrollTop(a(document).scrollTop()-g.scrollSpeed)}else{if(a(window).height()-(f.pageY-a(document).scrollTop())<g.scrollSensitivity){b=a(document).scrollTop(a(document).scrollTop()+g.scrollSpeed)}}if(f.pageX-a(document).scrollLeft()<g.scrollSensitivity){b=a(document).scrollLeft(a(document).scrollLeft()-g.scrollSpeed)}else{if(a(window).width()-(f.pageX-a(document).scrollLeft())<g.scrollSensitivity){b=a(document).scrollLeft(a(document).scrollLeft()+g.scrollSpeed)}}}if(b!==false&&a.ui.ddmanager&&!g.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,f)}}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y"){this.helper[0].style.left=this.position.left+"px"}if(!this.options.axis||this.options.axis!="x"){this.helper[0].style.top=this.position.top+"px"}for(var d=this.items.length-1;d>=0;d--){var e=this.items[d],c=e.item[0],h=this._intersectsWithPointer(e);if(!h){continue}if(c!=this.currentItem[0]&&this.placeholder[h==1?"next":"prev"]()[0]!=c&&!a.ui.contains(this.placeholder[0],c)&&(this.options.type=="semi-dynamic"?!a.ui.contains(this.element[0],c):true)){this.direction=h==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(e)){this._rearrange(f,e)}else{break}this._trigger("change",f,this._uiHash());break}}this._contactContainers(f);if(a.ui.ddmanager){a.ui.ddmanager.drag(this,f)}this._trigger("sort",f,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(c,d){if(!c){return}if(a.ui.ddmanager&&!this.options.dropBehaviour){a.ui.ddmanager.drop(this,c)}if(this.options.revert){var b=this;var e=b.placeholder.offset();b.reverting=true;a(this.helper).animate({left:e.left-this.offset.parent.left-b.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:e.top-this.offset.parent.top-b.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){b._clear(c)})}else{this._clear(c,d)}return false},cancel:function(){var b=this;if(this.dragging){this._mouseUp();if(this.options.helper=="original"){this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else{this.currentItem.show()}for(var c=this.containers.length-1;c>=0;c--){this.containers[c]._trigger("deactivate",null,b._uiHash(this));if(this.containers[c].containerCache.over){this.containers[c]._trigger("out",null,b._uiHash(this));this.containers[c].containerCache.over=0}}}if(this.placeholder[0].parentNode){this.placeholder[0].parentNode.removeChild(this.placeholder[0])}if(this.options.helper!="original"&&this.helper&&this.helper[0].parentNode){this.helper.remove()}a.extend(this,{helper:null,dragging:false,reverting:false,_noFinalSort:null});if(this.domPosition.prev){a(this.domPosition.prev).after(this.currentItem)}else{a(this.domPosition.parent).prepend(this.currentItem)}return true},serialize:function(d){var b=this._getItemsAsjQuery(d&&d.connected);var c=[];d=d||{};a(b).each(function(){var e=(a(d.item||this).attr(d.attribute||"id")||"").match(d.expression||(/(.+)[-=_](.+)/));if(e){c.push((d.key||e[1]+"[]")+"="+(d.key&&d.expression?e[1]:e[2]))}});return c.join("&")},toArray:function(d){var b=this._getItemsAsjQuery(d&&d.connected);var c=[];d=d||{};b.each(function(){c.push(a(d.item||this).attr(d.attribute||"id")||"")});return c},_intersectsWith:function(m){var e=this.positionAbs.left,d=e+this.helperProportions.width,k=this.positionAbs.top,j=k+this.helperProportions.height;var f=m.left,c=f+m.width,n=m.top,i=n+m.height;var o=this.offset.click.top,h=this.offset.click.left;var g=(k+o)>n&&(k+o)<i&&(e+h)>f&&(e+h)<c;if(this.options.tolerance=="pointer"||this.options.forcePointerForContainers||(this.options.tolerance!="pointer"&&this.helperProportions[this.floating?"width":"height"]>m[this.floating?"width":"height"])){return g}else{return(f<e+(this.helperProportions.width/2)&&d-(this.helperProportions.width/2)<c&&n<k+(this.helperProportions.height/2)&&j-(this.helperProportions.height/2)<i)}},_intersectsWithPointer:function(d){var e=a.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,d.top,d.height),c=a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,d.left,d.width),g=e&&c,b=this._getDragVerticalDirection(),f=this._getDragHorizontalDirection();if(!g){return false}return this.floating?(((f&&f=="right")||b=="down")?2:1):(b&&(b=="down"?2:1))},_intersectsWithSides:function(e){var c=a.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,e.top+(e.height/2),e.height),d=a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,e.left+(e.width/2),e.width),b=this._getDragVerticalDirection(),f=this._getDragHorizontalDirection();if(this.floating&&f){return((f=="right"&&d)||(f=="left"&&!d))}else{return b&&((b=="down"&&c)||(b=="up"&&!c))}},_getDragVerticalDirection:function(){var b=this.positionAbs.top-this.lastPositionAbs.top;return b!=0&&(b>0?"down":"up")},_getDragHorizontalDirection:function(){var b=this.positionAbs.left-this.lastPositionAbs.left;return b!=0&&(b>0?"right":"left")},refresh:function(b){this._refreshItems(b);this.refreshPositions()},_connectWith:function(){var b=this.options;return b.connectWith.constructor==String?[b.connectWith]:b.connectWith},_getItemsAsjQuery:function(b){var l=this;var g=[];var e=[];var h=this._connectWith();if(h&&b){for(var d=h.length-1;d>=0;d--){var k=a(h[d]);for(var c=k.length-1;c>=0;c--){var f=a.data(k[c],"sortable");if(f&&f!=this&&!f.options.disabled){e.push([a.isFunction(f.options.items)?f.options.items.call(f.element):a(f.options.items,f.element).not(".ui-sortable-helper"),f])}}}}e.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(".ui-sortable-helper"),this]);for(var d=e.length-1;d>=0;d--){e[d][0].each(function(){g.push(this)})}return a(g)},_removeCurrentsFromItems:function(){var d=this.currentItem.find(":data(sortable-item)");for(var c=0;c<this.items.length;c++){for(var b=0;b<d.length;b++){if(d[b]==this.items[c].item[0]){this.items.splice(c,1)}}}},_refreshItems:function(b){this.items=[];this.containers=[this];var h=this.items;var p=this;var f=[[a.isFunction(this.options.items)?this.options.items.call(this.element[0],b,{item:this.currentItem}):a(this.options.items,this.element),this]];var l=this._connectWith();if(l){for(var e=l.length-1;e>=0;e--){var m=a(l[e]);for(var d=m.length-1;d>=0;d--){var g=a.data(m[d],"sortable");if(g&&g!=this&&!g.options.disabled){f.push([a.isFunction(g.options.items)?g.options.items.call(g.element[0],b,{item:this.currentItem}):a(g.options.items,g.element),g]);this.containers.push(g)}}}}for(var e=f.length-1;e>=0;e--){var k=f[e][1];var c=f[e][0];for(var d=0,n=c.length;d<n;d++){var o=a(c[d]);o.data("sortable-item",k);h.push({item:o,instance:k,width:0,height:0,left:0,top:0})}}},refreshPositions:function(b){if(this.offsetParent&&this.helper){this.offset.parent=this._getParentOffset()}for(var d=this.items.length-1;d>=0;d--){var e=this.items[d];if(e.instance!=this.currentContainer&&this.currentContainer&&e.item[0]!=this.currentItem[0]){continue}var c=this.options.toleranceElement?a(this.options.toleranceElement,e.item):e.item;if(!b){e.width=c.outerWidth();e.height=c.outerHeight()}var f=c.offset();e.left=f.left;e.top=f.top}if(this.options.custom&&this.options.custom.refreshContainers){this.options.custom.refreshContainers.call(this)}else{for(var d=this.containers.length-1;d>=0;d--){var f=this.containers[d].element.offset();this.containers[d].containerCache.left=f.left;this.containers[d].containerCache.top=f.top;this.containers[d].containerCache.width=this.containers[d].element.outerWidth();this.containers[d].containerCache.height=this.containers[d].element.outerHeight()}}},_createPlaceholder:function(d){var b=d||this,e=b.options;if(!e.placeholder||e.placeholder.constructor==String){var c=e.placeholder;e.placeholder={element:function(){var f=a(document.createElement(b.currentItem[0].nodeName)).addClass(c||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!c){f.style.visibility="hidden"}return f},update:function(f,g){if(c&&!e.forcePlaceholderSize){return}if(!g.height()){g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10))}if(!g.width()){g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||0,10))}}}}b.placeholder=a(e.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);e.placeholder.update(b,b.placeholder)},_contactContainers:function(d){for(var c=this.containers.length-1;c>=0;c--){if(this._intersectsWith(this.containers[c].containerCache)){if(!this.containers[c].containerCache.over){if(this.currentContainer!=this.containers[c]){var h=10000;var g=null;var e=this.positionAbs[this.containers[c].floating?"left":"top"];for(var b=this.items.length-1;b>=0;b--){if(!a.ui.contains(this.containers[c].element[0],this.items[b].item[0])){continue}var f=this.items[b][this.containers[c].floating?"left":"top"];if(Math.abs(f-e)<h){h=Math.abs(f-e);g=this.items[b]}}if(!g&&!this.options.dropOnEmpty){continue}this.currentContainer=this.containers[c];g?this._rearrange(d,g,null,true):this._rearrange(d,null,this.containers[c].element,true);this._trigger("change",d,this._uiHash());this.containers[c]._trigger("change",d,this._uiHash(this));this.options.placeholder.update(this.currentContainer,this.placeholder)}this.containers[c]._trigger("over",d,this._uiHash(this));this.containers[c].containerCache.over=1}}else{if(this.containers[c].containerCache.over){this.containers[c]._trigger("out",d,this._uiHash(this));this.containers[c].containerCache.over=0}}}},_createHelper:function(c){var d=this.options;var b=a.isFunction(d.helper)?a(d.helper.apply(this.element[0],[c,this.currentItem])):(d.helper=="clone"?this.currentItem.clone():this.currentItem);if(!b.parents("body").length){a(d.appendTo!="parent"?d.appendTo:this.currentItem[0].parentNode)[0].appendChild(b[0])}if(b[0]==this.currentItem[0]){this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}}if(b[0].style.width==""||d.forceHelperSize){b.width(this.currentItem.width())}if(b[0].style.height==""||d.forceHelperSize){b.height(this.currentItem.height())}return b},_adjustOffsetFromHelper:function(b){if(b.left!=undefined){this.offset.click.left=b.left+this.margins.left}if(b.right!=undefined){this.offset.click.left=this.helperProportions.width-b.right+this.margins.left}if(b.top!=undefined){this.offset.click.top=b.top+this.margins.top}if(b.bottom!=undefined){this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top}},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])){b.left+=this.scrollParent.scrollLeft();b.top+=this.scrollParent.scrollTop()}if((this.offsetParent[0]==document.body)||(this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)){b={top:0,left:0}}return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var b=this.currentItem.position();return{top:b.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:b.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else{return{top:0,left:0}}},_cacheMargins:function(){this.margins={left:(parseInt(this.currentItem.css("marginLeft"),10)||0),top:(parseInt(this.currentItem.css("marginTop"),10)||0)}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e=this.options;if(e.containment=="parent"){e.containment=this.helper[0].parentNode}if(e.containment=="document"||e.containment=="window"){this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,a(e.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a(e.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]}if(!(/^(document|window|parent)$/).test(e.containment)){var c=a(e.containment)[0];var d=a(e.containment).offset();var b=(a(c).css("overflow")!="hidden");this.containment=[d.left+(parseInt(a(c).css("borderLeftWidth"),10)||0)+(parseInt(a(c).css("paddingLeft"),10)||0)-this.margins.left,d.top+(parseInt(a(c).css("borderTopWidth"),10)||0)+(parseInt(a(c).css("paddingTop"),10)||0)-this.margins.top,d.left+(b?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css("borderLeftWidth"),10)||0)-(parseInt(a(c).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,d.top+(b?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css("borderTopWidth"),10)||0)-(parseInt(a(c).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(f,h){if(!h){h=this.position}var c=f=="absolute"?1:-1;var e=this.options,b=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=(/(html|body)/i).test(b[0].tagName);return{top:(h.top+this.offset.relative.top*c+this.offset.parent.top*c-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():(g?0:b.scrollTop()))*c)),left:(h.left+this.offset.relative.left*c+this.offset.parent.left*c-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:b.scrollLeft())*c))}},_generatePosition:function(e){var h=this.options,b=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,i=(/(html|body)/i).test(b[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0])){this.offset.relative=this._getRelativeOffset()}var d=e.pageX;var c=e.pageY;if(this.originalPosition){if(this.containment){if(e.pageX-this.offset.click.left<this.containment[0]){d=this.containment[0]+this.offset.click.left}if(e.pageY-this.offset.click.top<this.containment[1]){c=this.containment[1]+this.offset.click.top}if(e.pageX-this.offset.click.left>this.containment[2]){d=this.containment[2]+this.offset.click.left}if(e.pageY-this.offset.click.top>this.containment[3]){c=this.containment[3]+this.offset.click.top}}if(h.grid){var g=this.originalPageY+Math.round((c-this.originalPageY)/h.grid[1])*h.grid[1];c=this.containment?(!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:(!(g-this.offset.click.top<this.containment[1])?g-h.grid[1]:g+h.grid[1])):g;var f=this.originalPageX+Math.round((d-this.originalPageX)/h.grid[0])*h.grid[0];d=this.containment?(!(f-this.offset.click.left<this.containment[0]||f-this.offset.click.left>this.containment[2])?f:(!(f-this.offset.click.left<this.containment[0])?f-h.grid[0]:f+h.grid[0])):f}}return{top:(c-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():(i?0:b.scrollTop())))),left:(d-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():i?0:b.scrollLeft())))}},_rearrange:function(g,f,c,e){c?c[0].appendChild(this.placeholder[0]):f.item[0].parentNode.insertBefore(this.placeholder[0],(this.direction=="down"?f.item[0]:f.item[0].nextSibling));this.counter=this.counter?++this.counter:1;var d=this,b=this.counter;window.setTimeout(function(){if(b==d.counter){d.refreshPositions(!e)}},0)},_clear:function(d,e){this.reverting=false;var f=[],b=this;if(!this._noFinalSort&&this.currentItem[0].parentNode){this.placeholder.before(this.currentItem)}this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var c in this._storedCSS){if(this._storedCSS[c]=="auto"||this._storedCSS[c]=="static"){this._storedCSS[c]=""}}this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else{this.currentItem.show()}if(this.fromOutside&&!e){f.push(function(g){this._trigger("receive",g,this._uiHash(this.fromOutside))})}if((this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!e){f.push(function(g){this._trigger("update",g,this._uiHash())})}if(!a.ui.contains(this.element[0],this.currentItem[0])){if(!e){f.push(function(g){this._trigger("remove",g,this._uiHash())})}for(var c=this.containers.length-1;c>=0;c--){if(a.ui.contains(this.containers[c].element[0],this.currentItem[0])&&!e){f.push((function(g){return function(h){g._trigger("receive",h,this._uiHash(this))}}).call(this,this.containers[c]));f.push((function(g){return function(h){g._trigger("update",h,this._uiHash(this))}}).call(this,this.containers[c]))}}}for(var c=this.containers.length-1;c>=0;c--){if(!e){f.push((function(g){return function(h){g._trigger("deactivate",h,this._uiHash(this))}}).call(this,this.containers[c]))}if(this.containers[c].containerCache.over){f.push((function(g){return function(h){g._trigger("out",h,this._uiHash(this))}}).call(this,this.containers[c]));this.containers[c].containerCache.over=0}}if(this._storedCursor){a("body").css("cursor",this._storedCursor)}if(this._storedOpacity){this.helper.css("opacity",this._storedOpacity)}if(this._storedZIndex){this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex)}this.dragging=false;if(this.cancelHelperRemoval){if(!e){this._trigger("beforeStop",d,this._uiHash());for(var c=0;c<f.length;c++){f[c].call(this,d)}this._trigger("stop",d,this._uiHash())}return false}if(!e){this._trigger("beforeStop",d,this._uiHash())}this.placeholder[0].parentNode.removeChild(this.placeholder[0]);if(this.helper[0]!=this.currentItem[0]){this.helper.remove()}this.helper=null;if(!e){for(var c=0;c<f.length;c++){f[c].call(this,d)}this._trigger("stop",d,this._uiHash())}this.fromOutside=false;return true},_trigger:function(){if(a.widget.prototype._trigger.apply(this,arguments)===false){this.cancel()}},_uiHash:function(c){var b=c||this;return{helper:b.helper,placeholder:b.placeholder||a([]),position:b.position,absolutePosition:b.positionAbs,offset:b.positionAbs,item:b.currentItem,sender:c?c.element:null}}}));a.extend(a.ui.sortable,{getter:"serialize toArray",version:"1.7.2",eventPrefix:"sort",defaults:{appendTo:"parent",axis:false,cancel:":input,option",connectWith:false,containment:false,cursor:"auto",cursorAt:false,delay:0,distance:1,dropOnEmpty:true,forcePlaceholderSize:false,forceHelperSize:false,grid:false,handle:false,helper:"original",items:"> *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1000}})})(jQuery);;/*
 * jQuery UI Tabs 1.7.2
 *
 * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI/Tabs
 *
 * Depends:
 *	ui.core.js
 */
(function(a){a.widget("ui.tabs",{_init:function(){if(this.options.deselectable!==undefined){this.options.collapsible=this.options.deselectable}this._tabify(true)},_setData:function(b,c){if(b=="selected"){if(this.options.collapsible&&c==this.options.selected){return}this.select(c)}else{this.options[b]=c;if(b=="deselectable"){this.options.collapsible=c}this._tabify()}},_tabId:function(b){return b.title&&b.title.replace(/\s/g,"_").replace(/[^A-Za-z0-9\-_:\.]/g,"")||this.options.idPrefix+a.data(b)},_sanitizeSelector:function(b){return b.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+a.data(this.list[0]));return a.cookie.apply(null,[b].concat(a.makeArray(arguments)))},_ui:function(c,b){return{tab:c,panel:b,index:this.anchors.index(c)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b=a(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(n){this.list=this.element.children("ul:first");this.lis=a("li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return a("a",this)[0]});this.panels=a([]);var p=this,d=this.options;var c=/^#.+/;this.anchors.each(function(r,o){var q=a(o).attr("href");var s=q.split("#")[0],u;if(s&&(s===location.toString().split("#")[0]||(u=a("base")[0])&&s===u.href)){q=o.hash;o.href=q}if(c.test(q)){p.panels=p.panels.add(p._sanitizeSelector(q))}else{if(q!="#"){a.data(o,"href.tabs",q);a.data(o,"load.tabs",q.replace(/#.*$/,""));var w=p._tabId(o);o.href="#"+w;var v=a("#"+w);if(!v.length){v=a(d.panelTemplate).attr("id",w).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(p.panels[r-1]||p.list);v.data("destroy.tabs",true)}p.panels=p.panels.add(v)}else{d.disabled.push(r)}}});if(n){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all");this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(d.selected===undefined){if(location.hash){this.anchors.each(function(q,o){if(o.hash==location.hash){d.selected=q;return false}})}if(typeof d.selected!="number"&&d.cookie){d.selected=parseInt(p._cookie(),10)}if(typeof d.selected!="number"&&this.lis.filter(".ui-tabs-selected").length){d.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))}d.selected=d.selected||0}else{if(d.selected===null){d.selected=-1}}d.selected=((d.selected>=0&&this.anchors[d.selected])||d.selected<0)?d.selected:0;d.disabled=a.unique(d.disabled.concat(a.map(this.lis.filter(".ui-state-disabled"),function(q,o){return p.lis.index(q)}))).sort();if(a.inArray(d.selected,d.disabled)!=-1){d.disabled.splice(a.inArray(d.selected,d.disabled),1)}this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active");if(d.selected>=0&&this.anchors.length){this.panels.eq(d.selected).removeClass("ui-tabs-hide");this.lis.eq(d.selected).addClass("ui-tabs-selected ui-state-active");p.element.queue("tabs",function(){p._trigger("show",null,p._ui(p.anchors[d.selected],p.panels[d.selected]))});this.load(d.selected)}a(window).bind("unload",function(){p.lis.add(p.anchors).unbind(".tabs");p.lis=p.anchors=p.panels=null})}else{d.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))}this.element[d.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");if(d.cookie){this._cookie(d.selected,d.cookie)}for(var g=0,m;(m=this.lis[g]);g++){a(m)[a.inArray(g,d.disabled)!=-1&&!a(m).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled")}if(d.cache===false){this.anchors.removeData("cache.tabs")}this.lis.add(this.anchors).unbind(".tabs");if(d.event!="mouseover"){var f=function(o,i){if(i.is(":not(.ui-state-disabled)")){i.addClass("ui-state-"+o)}};var j=function(o,i){i.removeClass("ui-state-"+o)};this.lis.bind("mouseover.tabs",function(){f("hover",a(this))});this.lis.bind("mouseout.tabs",function(){j("hover",a(this))});this.anchors.bind("focus.tabs",function(){f("focus",a(this).closest("li"))});this.anchors.bind("blur.tabs",function(){j("focus",a(this).closest("li"))})}var b,h;if(d.fx){if(a.isArray(d.fx)){b=d.fx[0];h=d.fx[1]}else{b=h=d.fx}}function e(i,o){i.css({display:""});if(a.browser.msie&&o.opacity){i[0].style.removeAttribute("filter")}}var k=h?function(i,o){a(i).closest("li").removeClass("ui-state-default").addClass("ui-tabs-selected ui-state-active");o.hide().removeClass("ui-tabs-hide").animate(h,h.duration||"normal",function(){e(o,h);p._trigger("show",null,p._ui(i,o[0]))})}:function(i,o){a(i).closest("li").removeClass("ui-state-default").addClass("ui-tabs-selected ui-state-active");o.removeClass("ui-tabs-hide");p._trigger("show",null,p._ui(i,o[0]))};var l=b?function(o,i){i.animate(b,b.duration||"normal",function(){p.lis.removeClass("ui-tabs-selected ui-state-active").addClass("ui-state-default");i.addClass("ui-tabs-hide");e(i,b);p.element.dequeue("tabs")})}:function(o,i,q){p.lis.removeClass("ui-tabs-selected ui-state-active").addClass("ui-state-default");i.addClass("ui-tabs-hide");p.element.dequeue("tabs")};this.anchors.bind(d.event+".tabs",function(){var o=this,r=a(this).closest("li"),i=p.panels.filter(":not(.ui-tabs-hide)"),q=a(p._sanitizeSelector(this.hash));if((r.hasClass("ui-tabs-selected")&&!d.collapsible)||r.hasClass("ui-state-disabled")||r.hasClass("ui-state-processing")||p._trigger("select",null,p._ui(this,q[0]))===false){this.blur();return false}d.selected=p.anchors.index(this);p.abort();if(d.collapsible){if(r.hasClass("ui-tabs-selected")){d.selected=-1;if(d.cookie){p._cookie(d.selected,d.cookie)}p.element.queue("tabs",function(){l(o,i)}).dequeue("tabs");this.blur();return false}else{if(!i.length){if(d.cookie){p._cookie(d.selected,d.cookie)}p.element.queue("tabs",function(){k(o,q)});p.load(p.anchors.index(this));this.blur();return false}}}if(d.cookie){p._cookie(d.selected,d.cookie)}if(q.length){if(i.length){p.element.queue("tabs",function(){l(o,i)})}p.element.queue("tabs",function(){k(o,q)});p.load(p.anchors.index(this))}else{throw"jQuery UI Tabs: Mismatching fragment identifier."}if(a.browser.msie){this.blur()}});this.anchors.bind("click.tabs",function(){return false})},destroy:function(){var b=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var c=a.data(this,"href.tabs");if(c){this.href=c}var d=a(this).unbind(".tabs");a.each(["href","load","cache"],function(e,f){d.removeData(f+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){if(a.data(this,"destroy.tabs")){a(this).remove()}else{a(this).removeClass(["ui-state-default","ui-corner-top","ui-tabs-selected","ui-state-active","ui-state-hover","ui-state-focus","ui-state-disabled","ui-tabs-panel","ui-widget-content","ui-corner-bottom","ui-tabs-hide"].join(" "))}});if(b.cookie){this._cookie(null,b.cookie)}},add:function(e,d,c){if(c===undefined){c=this.anchors.length}var b=this,g=this.options,i=a(g.tabTemplate.replace(/#\{href\}/g,e).replace(/#\{label\}/g,d)),h=!e.indexOf("#")?e.replace("#",""):this._tabId(a("a",i)[0]);i.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var f=a("#"+h);if(!f.length){f=a(g.panelTemplate).attr("id",h).data("destroy.tabs",true)}f.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(c>=this.lis.length){i.appendTo(this.list);f.appendTo(this.list[0].parentNode)}else{i.insertBefore(this.lis[c]);f.insertBefore(this.panels[c])}g.disabled=a.map(g.disabled,function(k,j){return k>=c?++k:k});this._tabify();if(this.anchors.length==1){i.addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){b._trigger("show",null,b._ui(b.anchors[0],b.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[c],this.panels[c]))},remove:function(b){var d=this.options,e=this.lis.eq(b).remove(),c=this.panels.eq(b).remove();if(e.hasClass("ui-tabs-selected")&&this.anchors.length>1){this.select(b+(b+1<this.anchors.length?1:-1))}d.disabled=a.map(a.grep(d.disabled,function(g,f){return g!=b}),function(g,f){return g>=b?--g:g});this._tabify();this._trigger("remove",null,this._ui(e.find("a")[0],c[0]))},enable:function(b){var c=this.options;if(a.inArray(b,c.disabled)==-1){return}this.lis.eq(b).removeClass("ui-state-disabled");c.disabled=a.grep(c.disabled,function(e,d){return e!=b});this._trigger("enable",null,this._ui(this.anchors[b],this.panels[b]))},disable:function(c){var b=this,d=this.options;if(c!=d.selected){this.lis.eq(c).addClass("ui-state-disabled");d.disabled.push(c);d.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[c],this.panels[c]))}},select:function(b){if(typeof b=="string"){b=this.anchors.index(this.anchors.filter("[href$="+b+"]"))}else{if(b===null){b=-1}}if(b==-1&&this.options.collapsible){b=this.options.selected}this.anchors.eq(b).trigger(this.options.event+".tabs")},load:function(e){var c=this,g=this.options,b=this.anchors.eq(e)[0],d=a.data(b,"load.tabs");this.abort();if(!d||this.element.queue("tabs").length!==0&&a.data(b,"cache.tabs")){this.element.dequeue("tabs");return}this.lis.eq(e).addClass("ui-state-processing");if(g.spinner){var f=a("span",b);f.data("label.tabs",f.html()).html(g.spinner)}this.xhr=a.ajax(a.extend({},g.ajaxOptions,{url:d,success:function(i,h){a(c._sanitizeSelector(b.hash)).html(i);c._cleanup();if(g.cache){a.data(b,"cache.tabs",true)}c._trigger("load",null,c._ui(c.anchors[e],c.panels[e]));try{g.ajaxOptions.success(i,h)}catch(j){}c.element.dequeue("tabs")}}))},abort:function(){this.element.queue([]);this.panels.stop(false,true);if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup()},url:function(c,b){this.anchors.eq(c).removeData("cache.tabs").data("load.tabs",b)},length:function(){return this.anchors.length}});a.extend(a.ui.tabs,{version:"1.7.2",getter:"length",defaults:{ajaxOptions:null,cache:false,cookie:null,collapsible:false,disabled:[],event:"click",fx:null,idPrefix:"ui-tabs-",panelTemplate:"<div></div>",spinner:"<em>Loading&#8230;</em>",tabTemplate:'<li><a href="#{href}"><span>#{label}</span></a></li>'}});a.extend(a.ui.tabs.prototype,{rotation:null,rotate:function(d,f){var b=this,g=this.options;var c=b._rotate||(b._rotate=function(h){clearTimeout(b.rotation);b.rotation=setTimeout(function(){var i=g.selected;b.select(++i<b.anchors.length?i:0)},d);if(h){h.stopPropagation()}});var e=b._unrotate||(b._unrotate=!f?function(h){if(h.clientX){b.rotate(null)}}:function(h){t=g.selected;c()});if(d){this.element.bind("tabsshow",c);this.anchors.bind(g.event+".tabs",e);c()}else{clearTimeout(b.rotation);this.element.unbind("tabsshow",c);this.anchors.unbind(g.event+".tabs",e);delete this._rotate;delete this._unrotate}}})})(jQuery);;/*
 * jQuery UI Datepicker 1.7.2
 *
 * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI/Datepicker
 *
 * Depends:
 *	ui.core.js
 */
(function($){$.extend($.ui,{datepicker:{version:"1.7.2"}});var PROP_NAME="datepicker";function Datepicker(){this.debug=false;this._curInst=null;this._keyEvent=false;this._disabledInputs=[];this._datepickerShowing=false;this._inDialog=false;this._mainDivId="ui-datepicker-div";this._inlineClass="ui-datepicker-inline";this._appendClass="ui-datepicker-append";this._triggerClass="ui-datepicker-trigger";this._dialogClass="ui-datepicker-dialog";this._disableClass="ui-datepicker-disabled";this._unselectableClass="ui-datepicker-unselectable";this._currentClass="ui-datepicker-current-day";this._dayOverClass="ui-datepicker-days-cell-over";this.regional=[];this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],dateFormat:"mm/dd/yy",firstDay:0,isRTL:false};this._defaults={showOn:"focus",showAnim:"show",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:false,hideIfNoPrevNext:false,navigationAsDateFormat:false,gotoCurrent:false,changeMonth:false,changeYear:false,showMonthAfterYear:false,yearRange:"-10:+10",showOtherMonths:false,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"normal",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:true,showButtonPanel:false};$.extend(this._defaults,this.regional[""]);this.dpDiv=$('<div id="'+this._mainDivId+'" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all ui-helper-hidden-accessible"></div>')}$.extend(Datepicker.prototype,{markerClassName:"hasDatepicker",log:function(){if(this.debug){console.log.apply("",arguments)}},setDefaults:function(settings){extendRemove(this._defaults,settings||{});return this},_attachDatepicker:function(target,settings){var inlineSettings=null;for(var attrName in this._defaults){var attrValue=target.getAttribute("date:"+attrName);if(attrValue){inlineSettings=inlineSettings||{};try{inlineSettings[attrName]=eval(attrValue)}catch(err){inlineSettings[attrName]=attrValue}}}var nodeName=target.nodeName.toLowerCase();var inline=(nodeName=="div"||nodeName=="span");if(!target.id){target.id="dp"+(++this.uuid)}var inst=this._newInst($(target),inline);inst.settings=$.extend({},settings||{},inlineSettings||{});if(nodeName=="input"){this._connectDatepicker(target,inst)}else{if(inline){this._inlineDatepicker(target,inst)}}},_newInst:function(target,inline){var id=target[0].id.replace(/([:\[\]\.])/g,"\\\\$1");return{id:id,input:target,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:inline,dpDiv:(!inline?this.dpDiv:$('<div class="'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))}},_connectDatepicker:function(target,inst){var input=$(target);inst.append=$([]);inst.trigger=$([]);if(input.hasClass(this.markerClassName)){return}var appendText=this._get(inst,"appendText");var isRTL=this._get(inst,"isRTL");if(appendText){inst.append=$('<span class="'+this._appendClass+'">'+appendText+"</span>");input[isRTL?"before":"after"](inst.append)}var showOn=this._get(inst,"showOn");if(showOn=="focus"||showOn=="both"){input.focus(this._showDatepicker)}if(showOn=="button"||showOn=="both"){var buttonText=this._get(inst,"buttonText");var buttonImage=this._get(inst,"buttonImage");inst.trigger=$(this._get(inst,"buttonImageOnly")?$("<img/>").addClass(this._triggerClass).attr({src:buttonImage,alt:buttonText,title:buttonText}):$('<button type="button"></button>').addClass(this._triggerClass).html(buttonImage==""?buttonText:$("<img/>").attr({src:buttonImage,alt:buttonText,title:buttonText})));input[isRTL?"before":"after"](inst.trigger);inst.trigger.click(function(){if($.datepicker._datepickerShowing&&$.datepicker._lastInput==target){$.datepicker._hideDatepicker()}else{$.datepicker._showDatepicker(target)}return false})}input.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).bind("setData.datepicker",function(event,key,value){inst.settings[key]=value}).bind("getData.datepicker",function(event,key){return this._get(inst,key)});$.data(target,PROP_NAME,inst)},_inlineDatepicker:function(target,inst){var divSpan=$(target);if(divSpan.hasClass(this.markerClassName)){return}divSpan.addClass(this.markerClassName).append(inst.dpDiv).bind("setData.datepicker",function(event,key,value){inst.settings[key]=value}).bind("getData.datepicker",function(event,key){return this._get(inst,key)});$.data(target,PROP_NAME,inst);this._setDate(inst,this._getDefaultDate(inst));this._updateDatepicker(inst);this._updateAlternate(inst)},_dialogDatepicker:function(input,dateText,onSelect,settings,pos){var inst=this._dialogInst;if(!inst){var id="dp"+(++this.uuid);this._dialogInput=$('<input type="text" id="'+id+'" size="1" style="position: absolute; top: -100px;"/>');this._dialogInput.keydown(this._doKeyDown);$("body").append(this._dialogInput);inst=this._dialogInst=this._newInst(this._dialogInput,false);inst.settings={};$.data(this._dialogInput[0],PROP_NAME,inst)}extendRemove(inst.settings,settings||{});this._dialogInput.val(dateText);this._pos=(pos?(pos.length?pos:[pos.pageX,pos.pageY]):null);if(!this._pos){var browserWidth=window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth;var browserHeight=window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight;var scrollX=document.documentElement.scrollLeft||document.body.scrollLeft;var scrollY=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[(browserWidth/2)-100+scrollX,(browserHeight/2)-150+scrollY]}this._dialogInput.css("left",this._pos[0]+"px").css("top",this._pos[1]+"px");inst.settings.onSelect=onSelect;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);if($.blockUI){$.blockUI(this.dpDiv)}$.data(this._dialogInput[0],PROP_NAME,inst);return this},_destroyDatepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();$.removeData(target,PROP_NAME);if(nodeName=="input"){inst.append.remove();inst.trigger.remove();$target.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress)}else{if(nodeName=="div"||nodeName=="span"){$target.removeClass(this.markerClassName).empty()}}},_enableDatepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();if(nodeName=="input"){target.disabled=false;inst.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else{if(nodeName=="div"||nodeName=="span"){var inline=$target.children("."+this._inlineClass);inline.children().removeClass("ui-state-disabled")}}this._disabledInputs=$.map(this._disabledInputs,function(value){return(value==target?null:value)})},_disableDatepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();if(nodeName=="input"){target.disabled=true;inst.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else{if(nodeName=="div"||nodeName=="span"){var inline=$target.children("."+this._inlineClass);inline.children().addClass("ui-state-disabled")}}this._disabledInputs=$.map(this._disabledInputs,function(value){return(value==target?null:value)});this._disabledInputs[this._disabledInputs.length]=target},_isDisabledDatepicker:function(target){if(!target){return false}for(var i=0;i<this._disabledInputs.length;i++){if(this._disabledInputs[i]==target){return true}}return false},_getInst:function(target){try{return $.data(target,PROP_NAME)}catch(err){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(target,name,value){var inst=this._getInst(target);if(arguments.length==2&&typeof name=="string"){return(name=="defaults"?$.extend({},$.datepicker._defaults):(inst?(name=="all"?$.extend({},inst.settings):this._get(inst,name)):null))}var settings=name||{};if(typeof name=="string"){settings={};settings[name]=value}if(inst){if(this._curInst==inst){this._hideDatepicker(null)}var date=this._getDateDatepicker(target);extendRemove(inst.settings,settings);this._setDateDatepicker(target,date);this._updateDatepicker(inst)}},_changeDatepicker:function(target,name,value){this._optionDatepicker(target,name,value)},_refreshDatepicker:function(target){var inst=this._getInst(target);if(inst){this._updateDatepicker(inst)}},_setDateDatepicker:function(target,date,endDate){var inst=this._getInst(target);if(inst){this._setDate(inst,date,endDate);this._updateDatepicker(inst);this._updateAlternate(inst)}},_getDateDatepicker:function(target){var inst=this._getInst(target);if(inst&&!inst.inline){this._setDateFromField(inst)}return(inst?this._getDate(inst):null)},_doKeyDown:function(event){var inst=$.datepicker._getInst(event.target);var handled=true;var isRTL=inst.dpDiv.is(".ui-datepicker-rtl");inst._keyEvent=true;if($.datepicker._datepickerShowing){switch(event.keyCode){case 9:$.datepicker._hideDatepicker(null,"");break;case 13:var sel=$("td."+$.datepicker._dayOverClass+", td."+$.datepicker._currentClass,inst.dpDiv);if(sel[0]){$.datepicker._selectDay(event.target,inst.selectedMonth,inst.selectedYear,sel[0])}else{$.datepicker._hideDatepicker(null,$.datepicker._get(inst,"duration"))}return false;break;case 27:$.datepicker._hideDatepicker(null,$.datepicker._get(inst,"duration"));break;case 33:$.datepicker._adjustDate(event.target,(event.ctrlKey?-$.datepicker._get(inst,"stepBigMonths"):-$.datepicker._get(inst,"stepMonths")),"M");break;case 34:$.datepicker._adjustDate(event.target,(event.ctrlKey?+$.datepicker._get(inst,"stepBigMonths"):+$.datepicker._get(inst,"stepMonths")),"M");break;case 35:if(event.ctrlKey||event.metaKey){$.datepicker._clearDate(event.target)}handled=event.ctrlKey||event.metaKey;break;case 36:if(event.ctrlKey||event.metaKey){$.datepicker._gotoToday(event.target)}handled=event.ctrlKey||event.metaKey;break;case 37:if(event.ctrlKey||event.metaKey){$.datepicker._adjustDate(event.target,(isRTL?+1:-1),"D")}handled=event.ctrlKey||event.metaKey;if(event.originalEvent.altKey){$.datepicker._adjustDate(event.target,(event.ctrlKey?-$.datepicker._get(inst,"stepBigMonths"):-$.datepicker._get(inst,"stepMonths")),"M")}break;case 38:if(event.ctrlKey||event.metaKey){$.datepicker._adjustDate(event.target,-7,"D")}handled=event.ctrlKey||event.metaKey;break;case 39:if(event.ctrlKey||event.metaKey){$.datepicker._adjustDate(event.target,(isRTL?-1:+1),"D")}handled=event.ctrlKey||event.metaKey;if(event.originalEvent.altKey){$.datepicker._adjustDate(event.target,(event.ctrlKey?+$.datepicker._get(inst,"stepBigMonths"):+$.datepicker._get(inst,"stepMonths")),"M")}break;case 40:if(event.ctrlKey||event.metaKey){$.datepicker._adjustDate(event.target,+7,"D")}handled=event.ctrlKey||event.metaKey;break;default:handled=false}}else{if(event.keyCode==36&&event.ctrlKey){$.datepicker._showDatepicker(this)}else{handled=false}}if(handled){event.preventDefault();event.stopPropagation()}},_doKeyPress:function(event){var inst=$.datepicker._getInst(event.target);if($.datepicker._get(inst,"constrainInput")){var chars=$.datepicker._possibleChars($.datepicker._get(inst,"dateFormat"));var chr=String.fromCharCode(event.charCode==undefined?event.keyCode:event.charCode);return event.ctrlKey||(chr<" "||!chars||chars.indexOf(chr)>-1)}},_showDatepicker:function(input){input=input.target||input;if(input.nodeName.toLowerCase()!="input"){input=$("input",input.parentNode)[0]}if($.datepicker._isDisabledDatepicker(input)||$.datepicker._lastInput==input){return}var inst=$.datepicker._getInst(input);var beforeShow=$.datepicker._get(inst,"beforeShow");extendRemove(inst.settings,(beforeShow?beforeShow.apply(input,[input,inst]):{}));$.datepicker._hideDatepicker(null,"");$.datepicker._lastInput=input;$.datepicker._setDateFromField(inst);if($.datepicker._inDialog){input.value=""}if(!$.datepicker._pos){$.datepicker._pos=$.datepicker._findPos(input);$.datepicker._pos[1]+=input.offsetHeight}var isFixed=false;$(input).parents().each(function(){isFixed|=$(this).css("position")=="fixed";return !isFixed});if(isFixed&&$.browser.opera){$.datepicker._pos[0]-=document.documentElement.scrollLeft;$.datepicker._pos[1]-=document.documentElement.scrollTop}var offset={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null;inst.rangeStart=null;inst.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});$.datepicker._updateDatepicker(inst);offset=$.datepicker._checkOffset(inst,offset,isFixed);inst.dpDiv.css({position:($.datepicker._inDialog&&$.blockUI?"static":(isFixed?"fixed":"absolute")),display:"none",left:offset.left+"px",top:offset.top+"px"});if(!inst.inline){var showAnim=$.datepicker._get(inst,"showAnim")||"show";var duration=$.datepicker._get(inst,"duration");var postProcess=function(){$.datepicker._datepickerShowing=true;if($.browser.msie&&parseInt($.browser.version,10)<7){$("iframe.ui-datepicker-cover").css({width:inst.dpDiv.width()+4,height:inst.dpDiv.height()+4})}};if($.effects&&$.effects[showAnim]){inst.dpDiv.show(showAnim,$.datepicker._get(inst,"showOptions"),duration,postProcess)}else{inst.dpDiv[showAnim](duration,postProcess)}if(duration==""){postProcess()}if(inst.input[0].type!="hidden"){inst.input[0].focus()}$.datepicker._curInst=inst}},_updateDatepicker:function(inst){var dims={width:inst.dpDiv.width()+4,height:inst.dpDiv.height()+4};var self=this;inst.dpDiv.empty().append(this._generateHTML(inst)).find("iframe.ui-datepicker-cover").css({width:dims.width,height:dims.height}).end().find("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a").bind("mouseout",function(){$(this).removeClass("ui-state-hover");if(this.className.indexOf("ui-datepicker-prev")!=-1){$(this).removeClass("ui-datepicker-prev-hover")}if(this.className.indexOf("ui-datepicker-next")!=-1){$(this).removeClass("ui-datepicker-next-hover")}}).bind("mouseover",function(){if(!self._isDisabledDatepicker(inst.inline?inst.dpDiv.parent()[0]:inst.input[0])){$(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");$(this).addClass("ui-state-hover");if(this.className.indexOf("ui-datepicker-prev")!=-1){$(this).addClass("ui-datepicker-prev-hover")}if(this.className.indexOf("ui-datepicker-next")!=-1){$(this).addClass("ui-datepicker-next-hover")}}}).end().find("."+this._dayOverClass+" a").trigger("mouseover").end();var numMonths=this._getNumberOfMonths(inst);var cols=numMonths[1];var width=17;if(cols>1){inst.dpDiv.addClass("ui-datepicker-multi-"+cols).css("width",(width*cols)+"em")}else{inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("")}inst.dpDiv[(numMonths[0]!=1||numMonths[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");inst.dpDiv[(this._get(inst,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");if(inst.input&&inst.input[0].type!="hidden"&&inst==$.datepicker._curInst){$(inst.input[0]).focus()}},_checkOffset:function(inst,offset,isFixed){var dpWidth=inst.dpDiv.outerWidth();var dpHeight=inst.dpDiv.outerHeight();var inputWidth=inst.input?inst.input.outerWidth():0;var inputHeight=inst.input?inst.input.outerHeight():0;var viewWidth=(window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth)+$(document).scrollLeft();var viewHeight=(window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight)+$(document).scrollTop();offset.left-=(this._get(inst,"isRTL")?(dpWidth-inputWidth):0);offset.left-=(isFixed&&offset.left==inst.input.offset().left)?$(document).scrollLeft():0;offset.top-=(isFixed&&offset.top==(inst.input.offset().top+inputHeight))?$(document).scrollTop():0;offset.left-=(offset.left+dpWidth>viewWidth&&viewWidth>dpWidth)?Math.abs(offset.left+dpWidth-viewWidth):0;offset.top-=(offset.top+dpHeight>viewHeight&&viewHeight>dpHeight)?Math.abs(offset.top+dpHeight+inputHeight*2-viewHeight):0;return offset},_findPos:function(obj){while(obj&&(obj.type=="hidden"||obj.nodeType!=1)){obj=obj.nextSibling}var position=$(obj).offset();return[position.left,position.top]},_hideDatepicker:function(input,duration){var inst=this._curInst;if(!inst||(input&&inst!=$.data(input,PROP_NAME))){return}if(inst.stayOpen){this._selectDate("#"+inst.id,this._formatDate(inst,inst.currentDay,inst.currentMonth,inst.currentYear))}inst.stayOpen=false;if(this._datepickerShowing){duration=(duration!=null?duration:this._get(inst,"duration"));var showAnim=this._get(inst,"showAnim");var postProcess=function(){$.datepicker._tidyDialog(inst)};if(duration!=""&&$.effects&&$.effects[showAnim]){inst.dpDiv.hide(showAnim,$.datepicker._get(inst,"showOptions"),duration,postProcess)}else{inst.dpDiv[(duration==""?"hide":(showAnim=="slideDown"?"slideUp":(showAnim=="fadeIn"?"fadeOut":"hide")))](duration,postProcess)}if(duration==""){this._tidyDialog(inst)}var onClose=this._get(inst,"onClose");if(onClose){onClose.apply((inst.input?inst.input[0]:null),[(inst.input?inst.input.val():""),inst])}this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if($.blockUI){$.unblockUI();$("body").append(this.dpDiv)}}this._inDialog=false}this._curInst=null},_tidyDialog:function(inst){inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(event){if(!$.datepicker._curInst){return}var $target=$(event.target);if(($target.parents("#"+$.datepicker._mainDivId).length==0)&&!$target.hasClass($.datepicker.markerClassName)&&!$target.hasClass($.datepicker._triggerClass)&&$.datepicker._datepickerShowing&&!($.datepicker._inDialog&&$.blockUI)){$.datepicker._hideDatepicker(null,"")}},_adjustDate:function(id,offset,period){var target=$(id);var inst=this._getInst(target[0]);if(this._isDisabledDatepicker(target[0])){return}this._adjustInstDate(inst,offset+(period=="M"?this._get(inst,"showCurrentAtPos"):0),period);this._updateDatepicker(inst)},_gotoToday:function(id){var target=$(id);var inst=this._getInst(target[0]);if(this._get(inst,"gotoCurrent")&&inst.currentDay){inst.selectedDay=inst.currentDay;inst.drawMonth=inst.selectedMonth=inst.currentMonth;inst.drawYear=inst.selectedYear=inst.currentYear}else{var date=new Date();inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear()}this._notifyChange(inst);this._adjustDate(target)},_selectMonthYear:function(id,select,period){var target=$(id);var inst=this._getInst(target[0]);inst._selectingMonthYear=false;inst["selected"+(period=="M"?"Month":"Year")]=inst["draw"+(period=="M"?"Month":"Year")]=parseInt(select.options[select.selectedIndex].value,10);this._notifyChange(inst);this._adjustDate(target)},_clickMonthYear:function(id){var target=$(id);var inst=this._getInst(target[0]);if(inst.input&&inst._selectingMonthYear&&!$.browser.msie){inst.input[0].focus()}inst._selectingMonthYear=!inst._selectingMonthYear},_selectDay:function(id,month,year,td){var target=$(id);if($(td).hasClass(this._unselectableClass)||this._isDisabledDatepicker(target[0])){return}var inst=this._getInst(target[0]);inst.selectedDay=inst.currentDay=$("a",td).html();inst.selectedMonth=inst.currentMonth=month;inst.selectedYear=inst.currentYear=year;if(inst.stayOpen){inst.endDay=inst.endMonth=inst.endYear=null}this._selectDate(id,this._formatDate(inst,inst.currentDay,inst.currentMonth,inst.currentYear));if(inst.stayOpen){inst.rangeStart=this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay));this._updateDatepicker(inst)}},_clearDate:function(id){var target=$(id);var inst=this._getInst(target[0]);inst.stayOpen=false;inst.endDay=inst.endMonth=inst.endYear=inst.rangeStart=null;this._selectDate(target,"")},_selectDate:function(id,dateStr){var target=$(id);var inst=this._getInst(target[0]);dateStr=(dateStr!=null?dateStr:this._formatDate(inst));if(inst.input){inst.input.val(dateStr)}this._updateAlternate(inst);var onSelect=this._get(inst,"onSelect");if(onSelect){onSelect.apply((inst.input?inst.input[0]:null),[dateStr,inst])}else{if(inst.input){inst.input.trigger("change")}}if(inst.inline){this._updateDatepicker(inst)}else{if(!inst.stayOpen){this._hideDatepicker(null,this._get(inst,"duration"));this._lastInput=inst.input[0];if(typeof(inst.input[0])!="object"){inst.input[0].focus()}this._lastInput=null}}},_updateAlternate:function(inst){var altField=this._get(inst,"altField");if(altField){var altFormat=this._get(inst,"altFormat")||this._get(inst,"dateFormat");var date=this._getDate(inst);dateStr=this.formatDate(altFormat,date,this._getFormatConfig(inst));$(altField).each(function(){$(this).val(dateStr)})}},noWeekends:function(date){var day=date.getDay();return[(day>0&&day<6),""]},iso8601Week:function(date){var checkDate=new Date(date.getFullYear(),date.getMonth(),date.getDate());var firstMon=new Date(checkDate.getFullYear(),1-1,4);var firstDay=firstMon.getDay()||7;firstMon.setDate(firstMon.getDate()+1-firstDay);if(firstDay<4&&checkDate<firstMon){checkDate.setDate(checkDate.getDate()-3);return $.datepicker.iso8601Week(checkDate)}else{if(checkDate>new Date(checkDate.getFullYear(),12-1,28)){firstDay=new Date(checkDate.getFullYear()+1,1-1,4).getDay()||7;if(firstDay>4&&(checkDate.getDay()||7)<firstDay-3){return 1}}}return Math.floor(((checkDate-firstMon)/86400000)/7)+1},parseDate:function(format,value,settings){if(format==null||value==null){throw"Invalid arguments"}value=(typeof value=="object"?value.toString():value+"");if(value==""){return null}var shortYearCutoff=(settings?settings.shortYearCutoff:null)||this._defaults.shortYearCutoff;var dayNamesShort=(settings?settings.dayNamesShort:null)||this._defaults.dayNamesShort;var dayNames=(settings?settings.dayNames:null)||this._defaults.dayNames;var monthNamesShort=(settings?settings.monthNamesShort:null)||this._defaults.monthNamesShort;var monthNames=(settings?settings.monthNames:null)||this._defaults.monthNames;var year=-1;var month=-1;var day=-1;var doy=-1;var literal=false;var lookAhead=function(match){var matches=(iFormat+1<format.length&&format.charAt(iFormat+1)==match);if(matches){iFormat++}return matches};var getNumber=function(match){lookAhead(match);var origSize=(match=="@"?14:(match=="y"?4:(match=="o"?3:2)));var size=origSize;var num=0;while(size>0&&iValue<value.length&&value.charAt(iValue)>="0"&&value.charAt(iValue)<="9"){num=num*10+parseInt(value.charAt(iValue++),10);size--}if(size==origSize){throw"Missing number at position "+iValue}return num};var getName=function(match,shortNames,longNames){var names=(lookAhead(match)?longNames:shortNames);var size=0;for(var j=0;j<names.length;j++){size=Math.max(size,names[j].length)}var name="";var iInit=iValue;while(size>0&&iValue<value.length){name+=value.charAt(iValue++);for(var i=0;i<names.length;i++){if(name==names[i]){return i+1}}size--}throw"Unknown name at position "+iInit};var checkLiteral=function(){if(value.charAt(iValue)!=format.charAt(iFormat)){throw"Unexpected literal at position "+iValue}iValue++};var iValue=0;for(var iFormat=0;iFormat<format.length;iFormat++){if(literal){if(format.charAt(iFormat)=="'"&&!lookAhead("'")){literal=false}else{checkLiteral()}}else{switch(format.charAt(iFormat)){case"d":day=getNumber("d");break;case"D":getName("D",dayNamesShort,dayNames);break;case"o":doy=getNumber("o");break;case"m":month=getNumber("m");break;case"M":month=getName("M",monthNamesShort,monthNames);break;case"y":year=getNumber("y");break;case"@":var date=new Date(getNumber("@"));year=date.getFullYear();month=date.getMonth()+1;day=date.getDate();break;case"'":if(lookAhead("'")){checkLiteral()}else{literal=true}break;default:checkLiteral()}}}if(year==-1){year=new Date().getFullYear()}else{if(year<100){year+=new Date().getFullYear()-new Date().getFullYear()%100+(year<=shortYearCutoff?0:-100)}}if(doy>-1){month=1;day=doy;do{var dim=this._getDaysInMonth(year,month-1);if(day<=dim){break}month++;day-=dim}while(true)}var date=this._daylightSavingAdjust(new Date(year,month-1,day));if(date.getFullYear()!=year||date.getMonth()+1!=month||date.getDate()!=day){throw"Invalid date"}return date},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TIMESTAMP:"@",W3C:"yy-mm-dd",formatDate:function(format,date,settings){if(!date){return""}var dayNamesShort=(settings?settings.dayNamesShort:null)||this._defaults.dayNamesShort;var dayNames=(settings?settings.dayNames:null)||this._defaults.dayNames;var monthNamesShort=(settings?settings.monthNamesShort:null)||this._defaults.monthNamesShort;var monthNames=(settings?settings.monthNames:null)||this._defaults.monthNames;var lookAhead=function(match){var matches=(iFormat+1<format.length&&format.charAt(iFormat+1)==match);if(matches){iFormat++}return matches};var formatNumber=function(match,value,len){var num=""+value;if(lookAhead(match)){while(num.length<len){num="0"+num}}return num};var formatName=function(match,value,shortNames,longNames){return(lookAhead(match)?longNames[value]:shortNames[value])};var output="";var literal=false;if(date){for(var iFormat=0;iFormat<format.length;iFormat++){if(literal){if(format.charAt(iFormat)=="'"&&!lookAhead("'")){literal=false}else{output+=format.charAt(iFormat)}}else{switch(format.charAt(iFormat)){case"d":output+=formatNumber("d",date.getDate(),2);break;case"D":output+=formatName("D",date.getDay(),dayNamesShort,dayNames);break;case"o":var doy=date.getDate();for(var m=date.getMonth()-1;m>=0;m--){doy+=this._getDaysInMonth(date.getFullYear(),m)}output+=formatNumber("o",doy,3);break;case"m":output+=formatNumber("m",date.getMonth()+1,2);break;case"M":output+=formatName("M",date.getMonth(),monthNamesShort,monthNames);break;case"y":output+=(lookAhead("y")?date.getFullYear():(date.getYear()%100<10?"0":"")+date.getYear()%100);break;case"@":output+=date.getTime();break;case"'":if(lookAhead("'")){output+="'"}else{literal=true}break;default:output+=format.charAt(iFormat)}}}}return output},_possibleChars:function(format){var chars="";var literal=false;for(var iFormat=0;iFormat<format.length;iFormat++){if(literal){if(format.charAt(iFormat)=="'"&&!lookAhead("'")){literal=false}else{chars+=format.charAt(iFormat)}}else{switch(format.charAt(iFormat)){case"d":case"m":case"y":case"@":chars+="0123456789";break;case"D":case"M":return null;case"'":if(lookAhead("'")){chars+="'"}else{literal=true}break;default:chars+=format.charAt(iFormat)}}}return chars},_get:function(inst,name){return inst.settings[name]!==undefined?inst.settings[name]:this._defaults[name]},_setDateFromField:function(inst){var dateFormat=this._get(inst,"dateFormat");var dates=inst.input?inst.input.val():null;inst.endDay=inst.endMonth=inst.endYear=null;var date=defaultDate=this._getDefaultDate(inst);var settings=this._getFormatConfig(inst);try{date=this.parseDate(dateFormat,dates,settings)||defaultDate}catch(event){this.log(event);date=defaultDate}inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear();inst.currentDay=(dates?date.getDate():0);inst.currentMonth=(dates?date.getMonth():0);inst.currentYear=(dates?date.getFullYear():0);this._adjustInstDate(inst)},_getDefaultDate:function(inst){var date=this._determineDate(this._get(inst,"defaultDate"),new Date());var minDate=this._getMinMaxDate(inst,"min",true);var maxDate=this._getMinMaxDate(inst,"max");date=(minDate&&date<minDate?minDate:date);date=(maxDate&&date>maxDate?maxDate:date);return date},_determineDate:function(date,defaultDate){var offsetNumeric=function(offset){var date=new Date();date.setDate(date.getDate()+offset);return date};var offsetString=function(offset,getDaysInMonth){var date=new Date();var year=date.getFullYear();var month=date.getMonth();var day=date.getDate();var pattern=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g;var matches=pattern.exec(offset);while(matches){switch(matches[2]||"d"){case"d":case"D":day+=parseInt(matches[1],10);break;case"w":case"W":day+=parseInt(matches[1],10)*7;break;case"m":case"M":month+=parseInt(matches[1],10);day=Math.min(day,getDaysInMonth(year,month));break;case"y":case"Y":year+=parseInt(matches[1],10);day=Math.min(day,getDaysInMonth(year,month));break}matches=pattern.exec(offset)}return new Date(year,month,day)};date=(date==null?defaultDate:(typeof date=="string"?offsetString(date,this._getDaysInMonth):(typeof date=="number"?(isNaN(date)?defaultDate:offsetNumeric(date)):date)));date=(date&&date.toString()=="Invalid Date"?defaultDate:date);if(date){date.setHours(0);date.setMinutes(0);date.setSeconds(0);date.setMilliseconds(0)}return this._daylightSavingAdjust(date)},_daylightSavingAdjust:function(date){if(!date){return null}date.setHours(date.getHours()>12?date.getHours()+2:0);return date},_setDate:function(inst,date,endDate){var clear=!(date);var origMonth=inst.selectedMonth;var origYear=inst.selectedYear;date=this._determineDate(date,new Date());inst.selectedDay=inst.currentDay=date.getDate();inst.drawMonth=inst.selectedMonth=inst.currentMonth=date.getMonth();inst.drawYear=inst.selectedYear=inst.currentYear=date.getFullYear();if(origMonth!=inst.selectedMonth||origYear!=inst.selectedYear){this._notifyChange(inst)}this._adjustInstDate(inst);if(inst.input){inst.input.val(clear?"":this._formatDate(inst))}},_getDate:function(inst){var startDate=(!inst.currentYear||(inst.input&&inst.input.val()=="")?null:this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));return startDate},_generateHTML:function(inst){var today=new Date();today=this._daylightSavingAdjust(new Date(today.getFullYear(),today.getMonth(),today.getDate()));var isRTL=this._get(inst,"isRTL");var showButtonPanel=this._get(inst,"showButtonPanel");var hideIfNoPrevNext=this._get(inst,"hideIfNoPrevNext");var navigationAsDateFormat=this._get(inst,"navigationAsDateFormat");var numMonths=this._getNumberOfMonths(inst);var showCurrentAtPos=this._get(inst,"showCurrentAtPos");var stepMonths=this._get(inst,"stepMonths");var stepBigMonths=this._get(inst,"stepBigMonths");var isMultiMonth=(numMonths[0]!=1||numMonths[1]!=1);var currentDate=this._daylightSavingAdjust((!inst.currentDay?new Date(9999,9,9):new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));var minDate=this._getMinMaxDate(inst,"min",true);var maxDate=this._getMinMaxDate(inst,"max");var drawMonth=inst.drawMonth-showCurrentAtPos;var drawYear=inst.drawYear;if(drawMonth<0){drawMonth+=12;drawYear--}if(maxDate){var maxDraw=this._daylightSavingAdjust(new Date(maxDate.getFullYear(),maxDate.getMonth()-numMonths[1]+1,maxDate.getDate()));maxDraw=(minDate&&maxDraw<minDate?minDate:maxDraw);while(this._daylightSavingAdjust(new Date(drawYear,drawMonth,1))>maxDraw){drawMonth--;if(drawMonth<0){drawMonth=11;drawYear--}}}inst.drawMonth=drawMonth;inst.drawYear=drawYear;var prevText=this._get(inst,"prevText");prevText=(!navigationAsDateFormat?prevText:this.formatDate(prevText,this._daylightSavingAdjust(new Date(drawYear,drawMonth-stepMonths,1)),this._getFormatConfig(inst)));var prev=(this._canAdjustMonth(inst,-1,drawYear,drawMonth)?'<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery.datepicker._adjustDate(\'#'+inst.id+"', -"+stepMonths+", 'M');\" title=\""+prevText+'"><span class="ui-icon ui-icon-circle-triangle-'+(isRTL?"e":"w")+'">'+prevText+"</span></a>":(hideIfNoPrevNext?"":'<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+prevText+'"><span class="ui-icon ui-icon-circle-triangle-'+(isRTL?"e":"w")+'">'+prevText+"</span></a>"));var nextText=this._get(inst,"nextText");nextText=(!navigationAsDateFormat?nextText:this.formatDate(nextText,this._daylightSavingAdjust(new Date(drawYear,drawMonth+stepMonths,1)),this._getFormatConfig(inst)));var next=(this._canAdjustMonth(inst,+1,drawYear,drawMonth)?'<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery.datepicker._adjustDate(\'#'+inst.id+"', +"+stepMonths+", 'M');\" title=\""+nextText+'"><span class="ui-icon ui-icon-circle-triangle-'+(isRTL?"w":"e")+'">'+nextText+"</span></a>":(hideIfNoPrevNext?"":'<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+nextText+'"><span class="ui-icon ui-icon-circle-triangle-'+(isRTL?"w":"e")+'">'+nextText+"</span></a>"));var currentText=this._get(inst,"currentText");var gotoDate=(this._get(inst,"gotoCurrent")&&inst.currentDay?currentDate:today);currentText=(!navigationAsDateFormat?currentText:this.formatDate(currentText,gotoDate,this._getFormatConfig(inst)));var controls=(!inst.inline?'<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery.datepicker._hideDatepicker();">'+this._get(inst,"closeText")+"</button>":"");var buttonPanel=(showButtonPanel)?'<div class="ui-datepicker-buttonpane ui-widget-content">'+(isRTL?controls:"")+(this._isInRange(inst,gotoDate)?'<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery.datepicker._gotoToday(\'#'+inst.id+"');\">"+currentText+"</button>":"")+(isRTL?"":controls)+"</div>":"";var firstDay=parseInt(this._get(inst,"firstDay"),10);firstDay=(isNaN(firstDay)?0:firstDay);var dayNames=this._get(inst,"dayNames");var dayNamesShort=this._get(inst,"dayNamesShort");var dayNamesMin=this._get(inst,"dayNamesMin");var monthNames=this._get(inst,"monthNames");var monthNamesShort=this._get(inst,"monthNamesShort");var beforeShowDay=this._get(inst,"beforeShowDay");var showOtherMonths=this._get(inst,"showOtherMonths");var calculateWeek=this._get(inst,"calculateWeek")||this.iso8601Week;var endDate=inst.endDay?this._daylightSavingAdjust(new Date(inst.endYear,inst.endMonth,inst.endDay)):currentDate;var defaultDate=this._getDefaultDate(inst);var html="";for(var row=0;row<numMonths[0];row++){var group="";for(var col=0;col<numMonths[1];col++){var selectedDate=this._daylightSavingAdjust(new Date(drawYear,drawMonth,inst.selectedDay));var cornerClass=" ui-corner-all";var calender="";if(isMultiMonth){calender+='<div class="ui-datepicker-group ui-datepicker-group-';switch(col){case 0:calender+="first";cornerClass=" ui-corner-"+(isRTL?"right":"left");break;case numMonths[1]-1:calender+="last";cornerClass=" ui-corner-"+(isRTL?"left":"right");break;default:calender+="middle";cornerClass="";break}calender+='">'}calender+='<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix'+cornerClass+'">'+(/all|left/.test(cornerClass)&&row==0?(isRTL?next:prev):"")+(/all|right/.test(cornerClass)&&row==0?(isRTL?prev:next):"")+this._generateMonthYearHeader(inst,drawMonth,drawYear,minDate,maxDate,selectedDate,row>0||col>0,monthNames,monthNamesShort)+'</div><table class="ui-datepicker-calendar"><thead><tr>';var thead="";for(var dow=0;dow<7;dow++){var day=(dow+firstDay)%7;thead+="<th"+((dow+firstDay+6)%7>=5?' class="ui-datepicker-week-end"':"")+'><span title="'+dayNames[day]+'">'+dayNamesMin[day]+"</span></th>"}calender+=thead+"</tr></thead><tbody>";var daysInMonth=this._getDaysInMonth(drawYear,drawMonth);if(drawYear==inst.selectedYear&&drawMonth==inst.selectedMonth){inst.selectedDay=Math.min(inst.selectedDay,daysInMonth)}var leadDays=(this._getFirstDayOfMonth(drawYear,drawMonth)-firstDay+7)%7;var numRows=(isMultiMonth?6:Math.ceil((leadDays+daysInMonth)/7));var printDate=this._daylightSavingAdjust(new Date(drawYear,drawMonth,1-leadDays));for(var dRow=0;dRow<numRows;dRow++){calender+="<tr>";var tbody="";for(var dow=0;dow<7;dow++){var daySettings=(beforeShowDay?beforeShowDay.apply((inst.input?inst.input[0]:null),[printDate]):[true,""]);var otherMonth=(printDate.getMonth()!=drawMonth);var unselectable=otherMonth||!daySettings[0]||(minDate&&printDate<minDate)||(maxDate&&printDate>maxDate);tbody+='<td class="'+((dow+firstDay+6)%7>=5?" ui-datepicker-week-end":"")+(otherMonth?" ui-datepicker-other-month":"")+((printDate.getTime()==selectedDate.getTime()&&drawMonth==inst.selectedMonth&&inst._keyEvent)||(defaultDate.getTime()==printDate.getTime()&&defaultDate.getTime()==selectedDate.getTime())?" "+this._dayOverClass:"")+(unselectable?" "+this._unselectableClass+" ui-state-disabled":"")+(otherMonth&&!showOtherMonths?"":" "+daySettings[1]+(printDate.getTime()>=currentDate.getTime()&&printDate.getTime()<=endDate.getTime()?" "+this._currentClass:"")+(printDate.getTime()==today.getTime()?" ui-datepicker-today":""))+'"'+((!otherMonth||showOtherMonths)&&daySettings[2]?' title="'+daySettings[2]+'"':"")+(unselectable?"":" onclick=\"DP_jQuery.datepicker._selectDay('#"+inst.id+"',"+drawMonth+","+drawYear+', this);return false;"')+">"+(otherMonth?(showOtherMonths?printDate.getDate():"&#xa0;"):(unselectable?'<span class="ui-state-default">'+printDate.getDate()+"</span>":'<a class="ui-state-default'+(printDate.getTime()==today.getTime()?" ui-state-highlight":"")+(printDate.getTime()>=currentDate.getTime()&&printDate.getTime()<=endDate.getTime()?" ui-state-active":"")+'" href="#">'+printDate.getDate()+"</a>"))+"</td>";printDate.setDate(printDate.getDate()+1);printDate=this._daylightSavingAdjust(printDate)}calender+=tbody+"</tr>"}drawMonth++;if(drawMonth>11){drawMonth=0;drawYear++}calender+="</tbody></table>"+(isMultiMonth?"</div>"+((numMonths[0]>0&&col==numMonths[1]-1)?'<div class="ui-datepicker-row-break"></div>':""):"");group+=calender}html+=group}html+=buttonPanel+($.browser.msie&&parseInt($.browser.version,10)<7&&!inst.inline?'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>':"");inst._keyEvent=false;return html},_generateMonthYearHeader:function(inst,drawMonth,drawYear,minDate,maxDate,selectedDate,secondary,monthNames,monthNamesShort){minDate=(inst.rangeStart&&minDate&&selectedDate<minDate?selectedDate:minDate);var changeMonth=this._get(inst,"changeMonth");var changeYear=this._get(inst,"changeYear");var showMonthAfterYear=this._get(inst,"showMonthAfterYear");var html='<div class="ui-datepicker-title">';var monthHtml="";if(secondary||!changeMonth){monthHtml+='<span class="ui-datepicker-month">'+monthNames[drawMonth]+"</span> "}else{var inMinYear=(minDate&&minDate.getFullYear()==drawYear);var inMaxYear=(maxDate&&maxDate.getFullYear()==drawYear);monthHtml+='<select class="ui-datepicker-month" onchange="DP_jQuery.datepicker._selectMonthYear(\'#'+inst.id+"', this, 'M');\" onclick=\"DP_jQuery.datepicker._clickMonthYear('#"+inst.id+"');\">";for(var month=0;month<12;month++){if((!inMinYear||month>=minDate.getMonth())&&(!inMaxYear||month<=maxDate.getMonth())){monthHtml+='<option value="'+month+'"'+(month==drawMonth?' selected="selected"':"")+">"+monthNamesShort[month]+"</option>"}}monthHtml+="</select>"}if(!showMonthAfterYear){html+=monthHtml+((secondary||changeMonth||changeYear)&&(!(changeMonth&&changeYear))?"&#xa0;":"")}if(secondary||!changeYear){html+='<span class="ui-datepicker-year">'+drawYear+"</span>"}else{var years=this._get(inst,"yearRange").split(":");var year=0;var endYear=0;if(years.length!=2){year=drawYear-10;endYear=drawYear+10}else{if(years[0].charAt(0)=="+"||years[0].charAt(0)=="-"){year=drawYear+parseInt(years[0],10);endYear=drawYear+parseInt(years[1],10)}else{year=parseInt(years[0],10);endYear=parseInt(years[1],10)}}year=(minDate?Math.max(year,minDate.getFullYear()):year);endYear=(maxDate?Math.min(endYear,maxDate.getFullYear()):endYear);html+='<select class="ui-datepicker-year" onchange="DP_jQuery.datepicker._selectMonthYear(\'#'+inst.id+"', this, 'Y');\" onclick=\"DP_jQuery.datepicker._clickMonthYear('#"+inst.id+"');\">";for(;year<=endYear;year++){html+='<option value="'+year+'"'+(year==drawYear?' selected="selected"':"")+">"+year+"</option>"}html+="</select>"}if(showMonthAfterYear){html+=(secondary||changeMonth||changeYear?"&#xa0;":"")+monthHtml}html+="</div>";return html},_adjustInstDate:function(inst,offset,period){var year=inst.drawYear+(period=="Y"?offset:0);var month=inst.drawMonth+(period=="M"?offset:0);var day=Math.min(inst.selectedDay,this._getDaysInMonth(year,month))+(period=="D"?offset:0);var date=this._daylightSavingAdjust(new Date(year,month,day));var minDate=this._getMinMaxDate(inst,"min",true);var maxDate=this._getMinMaxDate(inst,"max");date=(minDate&&date<minDate?minDate:date);date=(maxDate&&date>maxDate?maxDate:date);inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear();if(period=="M"||period=="Y"){this._notifyChange(inst)}},_notifyChange:function(inst){var onChange=this._get(inst,"onChangeMonthYear");if(onChange){onChange.apply((inst.input?inst.input[0]:null),[inst.selectedYear,inst.selectedMonth+1,inst])}},_getNumberOfMonths:function(inst){var numMonths=this._get(inst,"numberOfMonths");return(numMonths==null?[1,1]:(typeof numMonths=="number"?[1,numMonths]:numMonths))},_getMinMaxDate:function(inst,minMax,checkRange){var date=this._determineDate(this._get(inst,minMax+"Date"),null);return(!checkRange||!inst.rangeStart?date:(!date||inst.rangeStart>date?inst.rangeStart:date))},_getDaysInMonth:function(year,month){return 32-new Date(year,month,32).getDate()},_getFirstDayOfMonth:function(year,month){return new Date(year,month,1).getDay()},_canAdjustMonth:function(inst,offset,curYear,curMonth){var numMonths=this._getNumberOfMonths(inst);var date=this._daylightSavingAdjust(new Date(curYear,curMonth+(offset<0?offset:numMonths[1]),1));if(offset<0){date.setDate(this._getDaysInMonth(date.getFullYear(),date.getMonth()))}return this._isInRange(inst,date)},_isInRange:function(inst,date){var newMinDate=(!inst.rangeStart?null:this._daylightSavingAdjust(new Date(inst.selectedYear,inst.selectedMonth,inst.selectedDay)));newMinDate=(newMinDate&&inst.rangeStart<newMinDate?inst.rangeStart:newMinDate);var minDate=newMinDate||this._getMinMaxDate(inst,"min");var maxDate=this._getMinMaxDate(inst,"max");return((!minDate||date>=minDate)&&(!maxDate||date<=maxDate))},_getFormatConfig:function(inst){var shortYearCutoff=this._get(inst,"shortYearCutoff");shortYearCutoff=(typeof shortYearCutoff!="string"?shortYearCutoff:new Date().getFullYear()%100+parseInt(shortYearCutoff,10));return{shortYearCutoff:shortYearCutoff,dayNamesShort:this._get(inst,"dayNamesShort"),dayNames:this._get(inst,"dayNames"),monthNamesShort:this._get(inst,"monthNamesShort"),monthNames:this._get(inst,"monthNames")}},_formatDate:function(inst,day,month,year){if(!day){inst.currentDay=inst.selectedDay;inst.currentMonth=inst.selectedMonth;inst.currentYear=inst.selectedYear}var date=(day?(typeof day=="object"?day:this._daylightSavingAdjust(new Date(year,month,day))):this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));return this.formatDate(this._get(inst,"dateFormat"),date,this._getFormatConfig(inst))}});function extendRemove(target,props){$.extend(target,props);for(var name in props){if(props[name]==null||props[name]==undefined){target[name]=props[name]}}return target}function isArray(a){return(a&&(($.browser.safari&&typeof a=="object"&&a.length)||(a.constructor&&a.constructor.toString().match(/\Array\(\)/))))}$.fn.datepicker=function(options){if(!$.datepicker.initialized){$(document).mousedown($.datepicker._checkExternalClick).find("body").append($.datepicker.dpDiv);$.datepicker.initialized=true}var otherArgs=Array.prototype.slice.call(arguments,1);if(typeof options=="string"&&(options=="isDisabled"||options=="getDate")){return $.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this[0]].concat(otherArgs))}if(options=="option"&&arguments.length==2&&typeof arguments[1]=="string"){return $.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this[0]].concat(otherArgs))}return this.each(function(){typeof options=="string"?$.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this].concat(otherArgs)):$.datepicker._attachDatepicker(this,options)})};$.datepicker=new Datepicker();$.datepicker.initialized=false;$.datepicker.uuid=new Date().getTime();$.datepicker.version="1.7.2";window.DP_jQuery=$})(jQuery);;
/*
    http://www.JSON.org/json2.js
    2008-05-25

    Public Domain.

    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.

    See http://www.JSON.org/js.html

    This file creates a global JSON object containing two methods: stringify
    and parse.

        JSON.stringify(value, replacer, space)
            value       any JavaScript value, usually an object or array.

            replacer    an optional parameter that determines how object
                        values are stringified for objects without a toJSON
                        method. It can be a function or an array.

            space       an optional parameter that specifies the indentation
                        of nested structures. If it is omitted, the text will
                        be packed without extra whitespace. If it is a number,
                        it will specify the number of spaces to indent at each
                        level. If it is a string (such as '\t' or '&nbsp;'),
                        it contains the characters used to indent at each level.

            This method produces a JSON text from a JavaScript value.

            When an object value is found, if the object contains a toJSON
            method, its toJSON method will be called and the result will be
            stringified. A toJSON method does not serialize: it returns the
            value represented by the name/value pair that should be serialized,
            or undefined if nothing should be serialized. The toJSON method
            will be passed the key associated with the value, and this will be
            bound to the object holding the key.

            For example, this would serialize Dates as ISO strings.

                Date.prototype.toJSON = function (key) {
                    function f(n) {
                        // Format integers to have at least two digits.
                        return n < 10 ? '0' + n : n;
                    }

                    return this.getUTCFullYear()   + '-' +
                         f(this.getUTCMonth() + 1) + '-' +
                         f(this.getUTCDate())      + 'T' +
                         f(this.getUTCHours())     + ':' +
                         f(this.getUTCMinutes())   + ':' +
                         f(this.getUTCSeconds())   + 'Z';
                };

            You can provide an optional replacer method. It will be passed the
            key and value of each member, with this bound to the containing
            object. The value that is returned from your method will be
            serialized. If your method returns undefined, then the member will
            be excluded from the serialization.

            If the replacer parameter is an array, then it will be used to
            select the members to be serialized. It filters the results such
            that only members with keys listed in the replacer array are
            stringified.

            Values that do not have JSON representations, such as undefined or
            functions, will not be serialized. Such values in objects will be
            dropped; in arrays they will be replaced with null. You can use
            a replacer function to replace those with JSON values.
            JSON.stringify(undefined) returns undefined.

            The optional space parameter produces a stringification of the
            value that is filled with line breaks and indentation to make it
            easier to read.

            If the space parameter is a non-empty string, then that string will
            be used for indentation. If the space parameter is a number, then
            the indentation will be that many spaces.

            Example:

            text = JSON.stringify(['e', {pluribus: 'unum'}]);
            // text is '["e",{"pluribus":"unum"}]'


            text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
            // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'

            text = JSON.stringify([new Date()], function (key, value) {
                return this[key] instanceof Date ?
                    'Date(' + this[key] + ')' : value;
            });
            // text is '["Date(---current time---)"]'


        JSON.parse(text, reviver)
            This method parses a JSON text to produce an object or array.
            It can throw a SyntaxError exception.

            The optional reviver parameter is a function that can filter and
            transform the results. It receives each of the keys and values,
            and its return value is used instead of the original value.
            If it returns what it received, then the structure is not modified.
            If it returns undefined then the member is deleted.

            Example:

            // Parse the text. Values that look like ISO date strings will
            // be converted to Date objects.

            myData = JSON.parse(text, function (key, value) {
                var a;
                if (typeof value === 'string') {
                    a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
                    if (a) {
                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
                            +a[5], +a[6]));
                    }
                }
                return value;
            });

            myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
                var d;
                if (typeof value === 'string' &&
                        value.slice(0, 5) === 'Date(' &&
                        value.slice(-1) === ')') {
                    d = new Date(value.slice(5, -1));
                    if (d) {
                        return d;
                    }
                }
                return value;
            });


    This is a reference implementation. You are free to copy, modify, or
    redistribute.

    This code should be minified before deployment.
    See http://javascript.crockford.com/jsmin.html

    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
    NOT CONTROL.
*/

/*jslint evil: true */

/*global JSON */

/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", call,
    charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, getUTCMinutes,
    getUTCMonth, getUTCSeconds, hasOwnProperty, join, lastIndex, length,
    parse, propertyIsEnumerable, prototype, push, replace, slice, stringify,
    test, toJSON, toString
*/

if (!this.JSON) {

// Create a JSON object only if one does not already exist. We create the
// object in a closure to avoid creating global variables.

    JSON = function () {

        function f(n) {
            // Format integers to have at least two digits.
            return n < 10 ? '0' + n : n;
        }

        Date.prototype.toJSON = function (key) {

            return this.getUTCFullYear()   + '-' +
                 f(this.getUTCMonth() + 1) + '-' +
                 f(this.getUTCDate())      + 'T' +
                 f(this.getUTCHours())     + ':' +
                 f(this.getUTCMinutes())   + ':' +
                 f(this.getUTCSeconds())   + 'Z';
        };

        var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
            escapeable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
            gap,
            indent,
            meta = {    // table of character substitutions
                '\b': '\\b',
                '\t': '\\t',
                '\n': '\\n',
                '\f': '\\f',
                '\r': '\\r',
                '"' : '\\"',
                '\\': '\\\\'
            },
            rep;


        function quote(string) {

// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.

            escapeable.lastIndex = 0;
            return escapeable.test(string) ?
                '"' + string.replace(escapeable, function (a) {
                    var c = meta[a];
                    if (typeof c === 'string') {
                        return c;
                    }
                    return '\\u' + ('0000' +
                            (+(a.charCodeAt(0))).toString(16)).slice(-4);
                }) + '"' :
                '"' + string + '"';
        }


        function str(key, holder) {

// Produce a string from holder[key].

            var i,          // The loop counter.
                k,          // The member key.
                v,          // The member value.
                length,
                mind = gap,
                partial,
                value = holder[key];

// If the value has a toJSON method, call it to obtain a replacement value.

            if (value && typeof value === 'object' &&
                    typeof value.toJSON === 'function') {
                value = value.toJSON(key);
            }

// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.

            if (typeof rep === 'function') {
                value = rep.call(holder, key, value);
            }

// What happens next depends on the value's type.

            switch (typeof value) {
            case 'string':
                return quote(value);

            case 'number':

// JSON numbers must be finite. Encode non-finite numbers as null.

                return isFinite(value) ? String(value) : 'null';

            case 'boolean':
            case 'null':

// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.

                return String(value);

// If the type is 'object', we might be dealing with an object or an array or
// null.

            case 'object':

// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.

                if (!value) {
                    return 'null';
                }

// Make an array to hold the partial results of stringifying this object value.

                gap += indent;
                partial = [];

// If the object has a dontEnum length property, we'll treat it as an array.

                if (typeof value.length === 'number' &&
                        !(value.propertyIsEnumerable('length'))) {

// The object is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.

                    length = value.length;
                    for (i = 0; i < length; i += 1) {
                        partial[i] = str(i, value) || 'null';
                    }

// Join all of the elements together, separated with commas, and wrap them in
// brackets.

                    v = partial.length === 0 ? '[]' :
                        gap ? '[\n' + gap +
                                partial.join(',\n' + gap) + '\n' +
                                    mind + ']' :
                              '[' + partial.join(',') + ']';
                    gap = mind;
                    return v;
                }

// If the replacer is an array, use it to select the members to be stringified.

                if (rep && typeof rep === 'object') {
                    length = rep.length;
                    for (i = 0; i < length; i += 1) {
                        k = rep[i];
                        if (typeof k === 'string') {
                            v = str(k, value, rep);
                            if (v) {
                                partial.push(quote(k) + (gap ? ': ' : ':') + v);
                            }
                        }
                    }
                } else {

// Otherwise, iterate through all of the keys in the object.

                    for (k in value) {
                        if (Object.hasOwnProperty.call(value, k)) {
                            v = str(k, value, rep);
                            if (v) {
                                partial.push(quote(k) + (gap ? ': ' : ':') + v);
                            }
                        }
                    }
                }

// Join all of the member texts together, separated with commas,
// and wrap them in braces.

                v = partial.length === 0 ? '{}' :
                    gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
                            mind + '}' : '{' + partial.join(',') + '}';
                gap = mind;
                return v;
            }
        }

// Return the JSON object containing the stringify and parse methods.

        return {
            stringify: function (value, replacer, space) {

// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.

                var i;
                gap = '';
                indent = '';

// If the space parameter is a number, make an indent string containing that
// many spaces.

                if (typeof space === 'number') {
                    for (i = 0; i < space; i += 1) {
                        indent += ' ';
                    }

// If the space parameter is a string, it will be used as the indent string.

                } else if (typeof space === 'string') {
                    indent = space;
                }

// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.

                rep = replacer;
                if (replacer && typeof replacer !== 'function' &&
                        (typeof replacer !== 'object' ||
                         typeof replacer.length !== 'number')) {
                    throw new Error('JSON.stringify');
                }

// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.

                return str('', {'': value});
            },


            parse: function (text, reviver) {

// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.

                var j;

                function walk(holder, key) {

// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.

                    var k, v, value = holder[key];
                    if (value && typeof value === 'object') {
                        for (k in value) {
                            if (Object.hasOwnProperty.call(value, k)) {
                                v = walk(value, k);
                                if (v !== undefined) {
                                    value[k] = v;
                                } else {
                                    delete value[k];
                                }
                            }
                        }
                    }
                    return reviver.call(holder, key, value);
                }


// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.

                cx.lastIndex = 0;
                if (cx.test(text)) {
                    text = text.replace(cx, function (a) {
                        return '\\u' + ('0000' +
                                (+(a.charCodeAt(0))).toString(16)).slice(-4);
                    });
                }

// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.

// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.

                if (/^[\],:{}\s]*$/.
test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {

// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.

                    j = eval('(' + text + ')');

// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.

                    return typeof reviver === 'function' ?
                        walk({'': j}, '') : j;
                }

// If the text is not JSON parseable, then a SyntaxError is thrown.

                throw new SyntaxError('JSON.parse');
            }
        };
    }();
}

(function($){function toIntegersAtLease(n)
{return n<10?'0'+n:n;}
Date.prototype.toJSON=function(date)
{return this.getUTCFullYear()+'-'+
toIntegersAtLease(this.getUTCMonth())+'-'+
toIntegersAtLease(this.getUTCDate());};var escapeable=/["\\\x00-\x1f\x7f-\x9f]/g;var meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};$.quoteString=function(string)
{if(escapeable.test(string))
{return'"'+string.replace(escapeable,function(a)
{var c=meta[a];if(typeof c==='string'){return c;}
c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16);})+'"';}
return'"'+string+'"';};$.toJSON=function(o,compact)
{var type=typeof(o);if(type=="undefined")
return"undefined";else if(type=="number"||type=="boolean")
return o+"";else if(o===null)
return"null";if(type=="string")
{return $.quoteString(o);}
if(type=="object"&&typeof o.toJSON=="function")
return o.toJSON(compact);if(type!="function"&&typeof(o.length)=="number")
{var ret=[];for(var i=0;i<o.length;i++){ret.push($.toJSON(o[i],compact));}
if(compact)
return"["+ret.join(",")+"]";else
return"["+ret.join(", ")+"]";}
if(type=="function"){throw new TypeError("Unable to convert object of type 'function' to json.");}
var ret=[];for(var k in o){var name;type=typeof(k);if(type=="number")
name='"'+k+'"';else if(type=="string")
name=$.quoteString(k);else
continue;var val=$.toJSON(o[k],compact);if(typeof(val)!="string"){continue;}
if(compact)
ret.push(name+":"+val);else
ret.push(name+": "+val);}
return"{"+ret.join(", ")+"}";};$.compactJSON=function(o)
{return $.toJSON(o,true);};$.evalJSON=function(src)
{return eval("("+src+")");};$.secureEvalJSON=function(src)
{var filtered=src;filtered=filtered.replace(/\\["\\\/bfnrtu]/g,'@');filtered=filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']');filtered=filtered.replace(/(?:^|:|,)(?:\s*\[)+/g,'');if(/^[\],:{}\s]*$/.test(filtered))
return eval("("+src+")");else
throw new SyntaxError("Error parsing JSON, source is not valid.");};})(jQuery);
/**
 * Cookie plugin
 *
 * Copyright (c) 2006 Klaus Hartl (stilbuero.de)
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 */

/**
 * Create a cookie with the given name and value and other optional parameters.
 *
 * @example $.cookie('the_cookie', 'the_value');
 * @desc Set the value of a cookie.
 * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
 * @desc Create a cookie with all available options.
 * @example $.cookie('the_cookie', 'the_value');
 * @desc Create a session cookie.
 * @example $.cookie('the_cookie', null);
 * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
 *       used when the cookie was set.
 *
 * @param String name The name of the cookie.
 * @param String value The value of the cookie.
 * @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
 * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
 *                             If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
 *                             If set to null or omitted, the cookie will be a session cookie and will not be retained
 *                             when the the browser exits.
 * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
 * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
 * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
 *                        require a secure protocol (like HTTPS).
 * @type undefined
 *
 * @name $.cookie
 * @cat Plugins/Cookie
 * @author Klaus Hartl/klaus.hartl@stilbuero.de
 */

/**
 * Get the value of a cookie with the given name.
 *
 * @example $.cookie('the_cookie');
 * @desc Get the value of a cookie.
 *
 * @param String name The name of the cookie.
 * @return The value of the cookie.
 * @type String
 *
 * @name $.cookie
 * @cat Plugins/Cookie
 * @author Klaus Hartl/klaus.hartl@stilbuero.de
 */
jQuery.cookie = function(name, value, options) {
    if (typeof value != 'undefined') { // name and value given, set cookie
        options = options || {};
        if (value === null) {
            value = '';
            options.expires = -1;
        }
        var expires = '';
        if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
            var date;
            if (typeof options.expires == 'number') {
                date = new Date();
                date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
            } else {
                date = options.expires;
            }
            expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
        }
        // CAUTION: Needed to parenthesize options.path and options.domain
        // in the following expressions, otherwise they evaluate to undefined
        // in the packed version for some reason...
        var path = options.path ? '; path=' + (options.path) : '';
        var domain = options.domain ? '; domain=' + (options.domain) : '';
        var secure = options.secure ? '; secure' : '';
        document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
    } else { // only name given, get cookie
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
};
/** 
 * JSON Cookie - jquery.jsoncookie.js
 *
 * Sets and retreives native JavaScript objects as cookies.
 * Depends on the object serialization framework provided by JSON2.
 *
 * Dependencies: jQuery, jQuery Cookie, JSON2
 * 
 * @project JSON Cookie
 * @author Randall Morey
 * @version 0.9
 */
(function ($) {
	var isObject = function (x) {
		return (typeof x === 'object') && !(x instanceof Array) && (x !== null);
	};
	
	$.extend({
		getJSONCookie: function (cookieName) {
			var cookieData = $.cookie(cookieName);
			return cookieData ? JSON.parse(cookieData) : {};
		},
		setJSONCookie: function (cookieName, data, options) {
			var cookieData = '';
			
			options = $.extend({
				expires: 90,
				path: '/'
			}, options);
			
			if (!isObject(data)) {	// data must be a true object to be serialized
				throw new Error('JSONCookie data must be an object');
			}
			
			cookieData = JSON.stringify(data);
			
			return $.cookie(cookieName, cookieData, options);
		},
		removeJSONCookie: function (cookieName) {
			return $.cookie(cookieName, null);
		},
		JSONCookie: function (cookieName, data, options) {
			if (data) {
				$.setJSONCookie(cookieName, data, options);
			}
			return $.getJSONCookie(cookieName);
		}
	});
})(jQuery);
/*
 * jquery.log.js
 * John Griffiths
 * 
 * simply allows you to do error logging & info 
 * without breaking other browsers
 * 
 */

jQuery.fn.debug = function(alertbox) {
  return this.each(function(){
    if (alertbox === null) { alert(this); }
  });
};

jQuery.log = function(message, alertbox) {
  if(window.console) {
     console.debug(message);
  } else if (alertbox === null) {
     alert(message);
  }
};
/*
 * jquery.nolink.js
 * Mat Ryer
 * 
 * nolink simply makes A tags not link anywhere -
 * instead the behaviour is managed by handling the click events
 * 
 */
(function($){
	
	$.fn.nolink = function() {
		return this.attr("href", "javascript:void(0);");
	}
	
})(jQuery);
/*
 *
 * Copyright (c) 2006-2009 Sam Collett (http://www.texotela.co.uk)
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * Version 2.2.4
 * Demo: http://www.texotela.co.uk/code/jquery/select/
 *
 * $LastChangedDate$
 * $Rev$
 *
 */
 
;(function($) {
 
/**
 * Adds (single/multiple) options to a select box (or series of select boxes)
 *
 * @name     addOption
 * @author   Sam Collett (http://www.texotela.co.uk)
 * @type     jQuery
 * @example  $("#myselect").addOption("Value", "Text"); // add single value (will be selected)
 * @example  $("#myselect").addOption("Value 2", "Text 2", false); // add single value (won't be selected)
 * @example  $("#myselect").addOption({"foo":"bar","bar":"baz"}, false); // add multiple values, but don't select
 *
 */
$.fn.addOption = function()
{
        var add = function(el, v, t, sO)
        {
                var option = document.createElement("option");
                option.value = v, option.text = t;
                // get options
                var o = el.options;
                // get number of options
                var oL = o.length;
                if(!el.cache)
                {
                        el.cache = {};
                        // loop through existing options, adding to cache
                        for(var i = 0; i < oL; i++)
                        {
                                el.cache[o[i].value] = i;
                        }
                }
                // add to cache if it isn't already
                if(typeof el.cache[v] == "undefined") el.cache[v] = oL;
                el.options[el.cache[v]] = option;
                if(sO)
                {
                        option.selected = true;
                }
        };
       
        var a = arguments;
        if(a.length == 0) return this;
        // select option when added? default is true
        var sO = true;
        // multiple items
        var m = false;
        // other variables
        var items, v, t;
        if(typeof(a[0]) == "object")
        {
                m = true;
                items = a[0];
        }
        if(a.length >= 2)
        {
                if(typeof(a[1]) == "boolean") sO = a[1];
                else if(typeof(a[2]) == "boolean") sO = a[2];
                if(!m)
                {
                        v = a[0];
                        t = a[1];
                }
        }
        this.each(
                function()
                {
                        if(this.nodeName.toLowerCase() != "select") return;
                        if(m)
                        {
                                for(var item in items)
                                {
                                        add(this, item, items[item], sO);
                                }
                        }
                        else
                        {
                                add(this, v, t, sO);
                        }
                }
        );
        return this;
};

/**
 * Add options via ajax
 *
 * @name     ajaxAddOption
 * @author   Sam Collett (http://www.texotela.co.uk)
 * @type     jQuery
 * @param    String url      Page to get options from (must be valid JSON)
 * @param    Object params   (optional) Any parameters to send with the request
 * @param    Boolean select  (optional) Select the added options, default true
 * @param    Function fn     (optional) Call this function with the select object as param after completion
 * @param    Array args      (optional) Array with params to pass to the function afterwards
 * @example  $("#myselect").ajaxAddOption("myoptions.php");
 * @example  $("#myselect").ajaxAddOption("myoptions.php", {"code" : "007"});
 * @example  $("#myselect").ajaxAddOption("myoptions.php", {"code" : "007"}, false, sortoptions, [{"dir": "desc"}]);
 *
 */
$.fn.ajaxAddOption = function(url, params, select, fn, args)
{
        if(typeof(url) != "string") return this;
        if(typeof(params) != "object") params = {};
        if(typeof(select) != "boolean") select = true;
        this.each(
                function()
                {
                        var el = this;
                        $.getJSON(url,
                                params,
                                function(r)
                                {
                                        $(el).addOption(r, select);
                                        if(typeof fn == "function")
                                        {
                                                if(typeof args == "object")
                                                {
                                                        fn.apply(el, args);
                                                }
                                                else
                                                {
                                                        fn.call(el);
                                                }
                                        }
                                }
                        );
                }
        );
        return this;
};

/**
 * Removes an option (by value or index) from a select box (or series of select boxes)
 *
 * @name     removeOption
 * @author   Sam Collett (http://www.texotela.co.uk)
 * @type     jQuery
 * @param    String|RegExp|Number what  Option to remove
 * @param    Boolean selectedOnly       (optional) Remove only if it has been selected (default false)  
 * @example  $("#myselect").removeOption("Value"); // remove by value
 * @example  $("#myselect").removeOption(/^val/i); // remove options with a value starting with 'val'
 * @example  $("#myselect").removeOption(/./); // remove all options
 * @example  $("#myselect").removeOption(/./, true); // remove all options that have been selected
 * @example  $("#myselect").removeOption(0); // remove by index
 * @example  $("#myselect").removeOption(["myselect_1","myselect_2"]); // values contained in passed array
 *
 */
$.fn.removeOption = function()
{
        var a = arguments;
        if(a.length == 0) return this;
        var ta = typeof(a[0]);
        var v, index;
        // has to be a string or regular expression (object in IE, function in Firefox)
        if(ta == "string" || ta == "object" || ta == "function" )
        {
                v = a[0];
                // if an array, remove items
                if(v.constructor == Array)
                {
                        var l = v.length;
                        for(var i = 0; i<l; i++)
                        {
                                this.removeOption(v[i], a[1]);
                        }
                        return this;
                }
        }
        else if(ta == "number") index = a[0];
        else return this;
        this.each(
                function()
                {
                        if(this.nodeName.toLowerCase() != "select") return;
                        // clear cache
                        if(this.cache) this.cache = null;
                        // does the option need to be removed?
                        var remove = false;
                        // get options
                        var o = this.options;
                        if(!!v)
                        {
                                // get number of options
                                var oL = o.length;
                                for(var i=oL-1; i>=0; i--)
                                {
                                        if(v.constructor == RegExp)
                                        {
                                                if(o[i].value.match(v))
                                                {
                                                        remove = true;
                                                }
                                        }
                                        else if(o[i].value == v)
                                        {
                                                remove = true;
                                        }
                                        // if the option is only to be removed if selected
                                        if(remove && a[1] === true) remove = o[i].selected;
                                        if(remove)
                                        {
                                                o[i] = null;
                                        }
                                        remove = false;
                                }
                        }
                        else
                        {
                                // only remove if selected?
                                if(a[1] === true)
                                {
                                        remove = o[index].selected;
                                }
                                else
                                {
                                        remove = true;
                                }
                                if(remove)
                                {
                                        this.remove(index);
                                }
                        }
                }
        );
        return this;
};


/**
 * Sort options (ascending or descending) in a select box (or series of select boxes)
 *
 * @name     sortOptions
 * @author   Sam Collett (http://www.texotela.co.uk)
 * @type     jQuery
 * @param    Boolean ascending   (optional) Sort ascending (true/undefined), or descending (false)
 * @example  // ascending
 * $("#myselect").sortOptions(); // or $("#myselect").sortOptions(true);
 * @example  // descending
 * $("#myselect").sortOptions(false);
 *
 */
$.fn.sortOptions = function(ascending)
{
        // get selected values first
        var sel = $(this).selectedValues();
        var a = typeof(ascending) == "undefined" ? true : !!ascending;
        this.each(
                function()
                {
                        if(this.nodeName.toLowerCase() != "select") return;
                        // get options
                        var o = this.options;
                        // get number of options
                        var oL = o.length;
                        // create an array for sorting
                        var sA = [];
                        // loop through options, adding to sort array
                        for(var i = 0; i<oL; i++)
                        {
                                sA[i] = {
                                        v: o[i].value,
                                        t: o[i].text
                                }
                        }
                        // sort items in array
                        sA.sort(
                                function(o1, o2)
                                {
                                        // option text is made lowercase for case insensitive sorting
                                        o1t = o1.t.toLowerCase(), o2t = o2.t.toLowerCase();
                                        // if options are the same, no sorting is needed
                                        if(o1t == o2t) return 0;
                                        if(a)
                                        {
                                                return o1t < o2t ? -1 : 1;
                                        }
                                        else
                                        {
                                                return o1t > o2t ? -1 : 1;
                                        }
                                }
                        );
                        // change the options to match the sort array
                        for(var i = 0; i<oL; i++)
                        {
                                o[i].text = sA[i].t;
                                o[i].value = sA[i].v;
                        }
                }
        ).selectOptions(sel, true); // select values, clearing existing ones
        return this;
};
/**
 * Selects an option by value
 *
 * @name     selectOptions
 * @author   Mathias Bank (http://www.mathias-bank.de), original function
 * @author   Sam Collett (http://www.texotela.co.uk), addition of regular expression matching
 * @type     jQuery
 * @param    String|RegExp|Array value  Which options should be selected
 * can be a string or regular expression, or an array of strings / regular expressions
 * @param    Boolean clear  Clear existing selected options, default false
 * @example  $("#myselect").selectOptions("val1"); // with the value 'val1'
 * @example  $("#myselect").selectOptions(["val1","val2","val3"]); // with the values 'val1' 'val2' 'val3'
 * @example  $("#myselect").selectOptions(/^val/i); // with the value starting with 'val', case insensitive
 *
 */
$.fn.selectOptions = function(value, clear)
{
        var v = value;
        var vT = typeof(value);
        // handle arrays
        if(vT == "object" && v.constructor == Array)
        {
                var $this = this;
                $.each(v, function()
                        {
                                $this.selectOptions(this, clear);
                        }
                );
        };
        var c = clear || false;
        // has to be a string or regular expression (object in IE, function in Firefox)
        if(vT != "string" && vT != "function" && vT != "object") return this;
        this.each(
                function()
                {
                        if(this.nodeName.toLowerCase() != "select") return this;
                        // get options
                        var o = this.options;
                        // get number of options
                        var oL = o.length;
                        for(var i = 0; i<oL; i++)
                        {
                                if(v.constructor == RegExp)
                                {
                                        if(o[i].value.match(v))
                                        {
                                                o[i].selected = true;
                                        }
                                        else if(c)
                                        {
                                                o[i].selected = false;
                                        }
                                }
                                else
                                {
                                        if(o[i].value == v)
                                        {
                                                o[i].selected = true;
                                        }
                                        else if(c)
                                        {
                                                o[i].selected = false;
                                        }
                                }
                        }
                }
        );
        return this;
};

/**
 * Copy options to another select
 *
 * @name     copyOptions
 * @author   Sam Collett (http://www.texotela.co.uk)
 * @type     jQuery
 * @param    String to  Element to copy to
 * @param    String which  (optional) Specifies which options should be copied - 'all' or 'selected'. Default is 'selected'
 * @example  $("#myselect").copyOptions("#myselect2"); // copy selected options from 'myselect' to 'myselect2'
 * @example  $("#myselect").copyOptions("#myselect2","selected"); // same as above
 * @example  $("#myselect").copyOptions("#myselect2","all"); // copy all options from 'myselect' to 'myselect2'
 *
 */
$.fn.copyOptions = function(to, which)
{
        var w = which || "selected";
        if($(to).size() == 0) return this;
        this.each(
                function()
                {
                        if(this.nodeName.toLowerCase() != "select") return this;
                        // get options
                        var o = this.options;
                        // get number of options
                        var oL = o.length;
                        for(var i = 0; i<oL; i++)
                        {
                                if(w == "all" || (w == "selected" && o[i].selected))
                                {
                                        $(to).addOption(o[i].value, o[i].text);
                                }
                        }
                }
        );
        return this;
};

/**
 * Checks if a select box has an option with the supplied value
 *
 * @name     containsOption
 * @author   Sam Collett (http://www.texotela.co.uk)
 * @type     Boolean|jQuery
 * @param    String|RegExp value  Which value to check for. Can be a string or regular expression
 * @param    Function fn          (optional) Function to apply if an option with the given value is found.
 * Use this if you don't want to break the chaining
 * @example  if($("#myselect").containsOption("val1")) alert("Has an option with the value 'val1'");
 * @example  if($("#myselect").containsOption(/^val/i)) alert("Has an option with the value starting with 'val'");
 * @example  $("#myselect").containsOption("val1", copyoption).doSomethingElseWithSelect(); // calls copyoption (user defined function) for any options found, chain is continued
 *
 */
$.fn.containsOption = function(value, fn)
{
        var found = false;
        var v = value;
        var vT = typeof(v);
        var fT = typeof(fn);
        // has to be a string or regular expression (object in IE, function in Firefox)
        if(vT != "string" && vT != "function" && vT != "object") return fT == "function" ? this: found;
        this.each(
                function()
                {
                        if(this.nodeName.toLowerCase() != "select") return this;
                        // option already found
                        if(found && fT != "function") return false;
                        // get options
                        var o = this.options;
                        // get number of options
                        var oL = o.length;
                        for(var i = 0; i<oL; i++)
                        {
                                if(v.constructor == RegExp)
                                {
                                        if (o[i].value.match(v))
                                        {
                                                found = true;
                                                if(fT == "function") fn.call(o[i], i);
                                        }
                                }
                                else
                                {
                                        if (o[i].value == v)
                                        {
                                                found = true;
                                                if(fT == "function") fn.call(o[i], i);
                                        }
                                }
                        }
                }
        );
        return fT == "function" ? this : found;
};


/**
 * Returns values which have been selected
 *
 * @name     selectedValues
 * @author   Sam Collett (http://www.texotela.co.uk)
 * @type     Array
 * @example  $("#myselect").selectedValues();
 *
 */
$.fn.selectedValues = function()
{
        var v = [];
        this.selectedOptions().each(
                function()
                {
                        v[v.length] = this.value;
                }
        );
        return v;
};

/**
 * Returns text which has been selected
 *
 * @name     selectedTexts
 * @author   Sam Collett (http://www.texotela.co.uk)
 * @type     Array
 * @example  $("#myselect").selectedTexts();
 *
 */
$.fn.selectedTexts = function()
{
        var t = [];
        this.selectedOptions().each(
                function()
                {
                        t[t.length] = this.text;
                }
        );
        return t;
};

/**
 * Returns options which have been selected
 *
 * @name     selectedOptions
 * @author   Sam Collett (http://www.texotela.co.uk)
 * @type     jQuery
 * @example  $("#myselect").selectedOptions();
 *
 */
$.fn.selectedOptions = function()
{
        return this.find("option:selected");
};

})(jQuery);
/*
 * clearingInput: a jQuery plugin
 *
 * clearingInput is a simple jQuery plugin that provides example/label text
 * inside text inputs that automatically clears when the input is focused.
 * Common uses are for a hint/example, or as a label when space is limited.
 *
 * For usage and examples, visit:
 * http://github.com/alexrabarts/jquery-clearinginput
 *
 * Licensed under the MIT:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * Copyright (c) 2008 Stateless Systems (http://statelesssystems.com)
 *
 * @author   Alex Rabarts (alexrabarts -at- gmail -dawt- com)
 * @requires jQuery v1.2 or later
 * @version  0.1
 */

(function ($) {
  $.extend($.fn, {
    clearingInput: function (options) {
      var defaults = {blurClass: 'blur'};

      options = $.extend(defaults, options);

      return this.each(function () {
        var input = $(this).addClass(options.blurClass);
        var form  = input.parents('form:first');
        var label, text;

        text = options.text || textFromLabel() || input.val();

        if (text) {
          input.val(text);

          input.blur(function () {
            if (input.val() === '') {
              input.val(text).addClass(options.blurClass);
            }
          }).focus(function () {
            if (input.val() === text) {
              input.val('');
            }
            input.removeClass(options.blurClass);
          });

          form.submit(function() {
            if (input.hasClass(options.blurClass)) {
              input.val('');
            }
          });

          input.blur();
        }

        function textFromLabel() {
          label = form.find('label[for=' + input.attr('id') + ']');
          // Position label off screen and use it for the input text
          return label ? label.css({position: 'absolute', left: '-9999px'}).text() : '';
        }
      });
    }
  });
})(jQuery);
/*

	objx core library
	
	Copyright (c) 2009 Mat Ryer, http://objx.googlecode.com/

	Permission is hereby granted, free of charge, to any person obtaining
	a copy of this software and associated documentation files (the
	"Software"), to deal in the Software without restriction, including
	without limitation the rights to use, copy, modify, merge, publish,
	distribute, sublicense, and/or sell copies of the Software, and to
	permit persons to whom the Software is furnished to do so, subject to
	the following conditions:

	The above copyright notice and this permission notice shall be
	included in all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
	MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
	LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
	OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
	WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
	
*/
eval(function(p,a,c,k,e,d){e=function(c){return(c<a?"":e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1;};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p;}('7 3=5(g){9(3.Z(g)){4 g}4 18 3.y.H(g)};3.12=w;3.19="2.0.10";3.y=3.X={13:w,f:U,H:5(g){8.g(g)},k:5(){7 C=[];C.u(8.f);j(7 i=0;i<6.c;i++){C.u(6[i])}3.k.P(3,C);4 8},m:5(){4 3.m(8.f)},g:5(){9(6.c===0){4 8.f}n{8.f=6[0]}4 8},L:5(){9(E 8.f.c=="W"){3.r("L","1b I 1a L 16 "+8.m()+" 17.")};4 8.f.c},J:5(){4"3:{("+8.m()+") "+8.f.J()+"}"}};3.y.H.X=3.y;3.q={};3.Z=5(o){9(o&&o.13){4 w}4 14};3.k=5(){9(3.12){9(6.c<2){3.r("3.k","1d 1h 1g 1i 1e 6 1f 1j 3.k(). 1n 1o://1p.1k.1l/p/3/1m/k")}}j(7 i=1;i<6.c;i++){j(7 G 1c 6[i]){6[0][G]=6[i][G]}}};3.1q=5(){7 M=6[0]||U;7 f=6[1]||8;7 v=[];j(7 i=2,l=6.c;i<l;i++){v.u(6[i])}4 5(){7 z=[];7 i=0;j(i=0,l=v.c;i<l;i++){z.u(v[i])}j(i=0,l=6.c;i<l;i++){z.u(6[i])}4 M.P(f,z)}};3.I=5(o,p){7 x=p.1F(".");9(x==-1){4 o[p]}4 3.I(o[p.R(0,x)],p.R(x+1))};3.O=5(d,Q){9(!3.q[d]){3.r("O","1G \\""+d+"\\" 1E 1C 1H \\""+Q+"\\" 1K S. 1I T S a <Y /> D?")}4 8};3.F=5(i,l){4(i>-1)?i:(l+(i))};3.1u=5(s,e,B){7 b={};b.t=3.F(s,B);9(e){b.h=3.F(e,B)}n 9(s<0){b.h=B-1}n{b.h=b.t}9(s&&e){s=N.1v(b.t,b.h);e=N.1t(b.t,b.h);b.t=s;b.h=e}4 b};3.15=5(d){9(3.q[d]){3.r("15","A d 1s \\""+d+"\\" 1w 1A 1B V. 1z T 1x a <Y /> D?")}3.q[d]=w};3.m=5(o){9(o&&E o=="1y"&&E o.c!="W"){4"K"}n{4 E o}};3.K=5(o){9(3.m(o)!="K"){4[o]}n{4 o}};3.V=5(d){4 3.q[d]||14};3.r=5(){7 D=6.c>1?6[0]:"1r";7 11=6[6.c-1];1J D+": "+11};3.J=5(){4"{3 1D}"};',62,109,'|||objx|return|function|arguments|var|this|if||range|length|plugin||_0|obj|end||for|extend||type|else|||__plugins|error||start|push|_1|true|dotPos|fn|theArgs||len|args|tag|typeof|index|property|init|get|toString|array|size|_3|Math|requires|apply|source|substring|missing|you|null|provided|undefined|prototype|script|isObjx||message|debug|_2|false|provides|of|objects|new|version|the|Cannot|in|Must|two|when|at|provide|least|using|google|com|wiki|See|http|code|bind|Error|called|max|indexRange|min|has|duplicated|object|Have|already|been|required|engine|is|indexOf|Plugin|by|Are|throw|but'.split('|'),0,{}))
objx.fn.is = function() {

	var passed = true;

	if (arguments.length === 1) {
	
		var objType = this.type();
	
		switch (arguments[0].toString()) {
		
			/*
			 *  Type descriptions
			 */
			case "string":
			case "number":
			case "boolean":
			case "function":
			case "object":
				passed = (objType == arguments[0].toString());
				break;
				
			/*
			 *  Special descriptions
			 */
			case "array":
				passed = (typeof this.obj().length != "undefined");
				break;

			case "something":
			
				var obj = this.obj();
			
				passed = (objType !== "undefined" && obj !== null);
				
				switch (objType) {
					case "string":
						passed = obj !== "";
						break;
					case "number":
						passed = obj !== 0;
						break;
				}
				
				break;
			
			/*
			 *  We don't know what you mean!?
			 */
			default:
				objx.error(".is() doesn't know what \"" + arguments[0].toString() + "\" is.  Remember that the descriptions are case sensitive.");
				break;
		}
	
	} else {
	
		if (!objx.provided("objx.each")) {
			objx.error("is", "Must include \"objx.each\" in order to support multiple argument overload of 'objx.is'.");
		}
	
		// handle each argument
		objx(arguments).each(
		
			// use bind to assign the first parameter
			objx.bind(
			
				// function to call .is() for each argument
				function(context, o) {
				
					// capture the 'passed' value
					passed = context.is(o);
					
					// return passed - to cancel the iteration if 'false'
					return passed;
					
				}, 
				
				// we dont care about binding context, just arguments
				null, 
				
				// the first argument should be this context
				this)
				
		);
		
	}

	return passed;

};

objx.provides("objx.is");
/*
 *  each
 *  Calls a function for each item in an object
 */

objx.requires("objx.is", "objx.each");
 
objx.fn.each = function() {

	if (objx.debug) {
		if (!arguments[0]) {
			objx.error("each", "You must pass a function as the first argument to 'each'.");
		}
	}

	var obj = this.obj();

	if (this.is("string")) {
		// handle strings explicitly
		for (var i = 0; i < this.size(); i++) {
			if (arguments[0].apply(this, [obj.charAt(i), i]) === false)
				break;
		}
	} else if (this.is("number")) {
		// call each for every number
		for (var i = 0; i < obj; i++) {
			if (arguments[0].apply(this, [i, i]) === false)
				break;
		}
	} else if (this.is("array")) {
		// handle array like objects
		for (var i = 0; i < this.size(); i++) {
			if (arguments[0].apply(this, [obj[i], i]) === false)
				break;
		}
	} else {
		// handle every other kind of object
		for (var prop in obj) {
			if (arguments[0].apply(this, [obj[prop], prop]) === false)
				break;
		}
	}
	
	return this;
	
};

objx.provides("objx.each");
/*
 *  objx(o).event("onSomething")
 *  Adds events to an object
 */

objx.requires("objx.is", "objx.event");

objx.fn.event = function() {

	// if no event name - throw exception
	if (arguments.length === 0 || !objx(arguments[0]).is("string", "something")) {
		objx.error("event", "You must provide an event name");
	}
	
	// get the event name
	var eventName = arguments[0],
		obj = this.obj();
	
	if (!this.is("something")) {
		objx.error("Cannot add events to objects of type " + this.type());
	}
	
	// add the events structure to the object
	obj.objx = obj.objx || {};
	obj.objx.event_listeners = obj.objx.event_listeners || {};
	obj.objx.event_listeners[eventName] = [];
	
	// add the lovely shortcut method
	obj[eventName] = (function(eName){
		
		// bind these
		var __eventName = eName;
		
		// return a function that will call the right event method
		return function(){
			
			// is the only argument a function?
			if (arguments.length == 1 && objx(arguments[0]).is("function")) {
			
				// add the listener
				this.listenFor[__eventName].apply(this, arguments);
				
			} else {
			
				// fire the event
				this.fire[__eventName].apply(this, arguments);
				
			}
			
			return this;
			
		};
		
	})(eventName);
	
	// add the fire item
	obj.fire = obj.fire || {};
	obj.fire[eventName] = objx.bind(function() { 

		// trigger each listener in the list
		objx(this.objx.event_listeners[eventName]).each(
		
			// bind the right context and arguments
			objx.bind(
			
				// the function to bind to
				function(args, item){
					return item.apply(this, args);
				},
				
				// 'this' is the object that is firing the event
				this,
				
				// these are any arguments specified
				arguments
			)
		);
		
	}, obj);
	
	// add the listenFor item
	obj.listenFor = obj.listenFor || {};
	obj.listenFor[eventName] = objx.bind(function(func) {
	
		// add the listener to the list
		this.objx.event_listeners[eventName].push(func);
		
	}, obj);
	
	// return this for chaining
	return this;
	
};

// shortcut reference object
objx.event = {};

objx.provides("objx.event");
/*
 *  class
 *
 *  Real object-orientation for JavaScript
 *
 *  objx.Class([base-class ,][mixin, ] class-definition);
 *
 *  
 *  base-class				The base class
 *  mixin					An object to be mixed in
 *	class-definition		An object defining the class
 *
 */
objx.Class = function() {

	var
		property,
	
		// create the constructor
		klass = function(){
		
			// call the "init" method
			this.init.apply(this, arguments);
			
		},
		
		// save the definition
		definition = arguments[arguments.length - 1]

	;
	
	// set a default init method
	klass.prototype.init = function(){};
	
	// loop through each inherits argument
	for (var i = 0, l = arguments.length - 1; i < l; i++) {

		// get this item
		var item = arguments[i];
		
		// is this a base class?
		if (typeof item == "function") {
			
			// this is a base class
		
			if (objx.debug) {
				if (klass.baseclass) {
					objx.error("Class", "Classes can have only 1 base class.");
				}
			}
		
			// set the baseclass
			klass.baseclass = item;
			
			// extend the prototype
			objx.extend(klass.prototype, item.prototype);
			
		} else {

			// extend the prototype with properties from this item
			objx.extend(klass.prototype, item);
			
		}
		
	}
	
	// create "base_" accessors where needed
	if (klass.baseclass) {
	
		// add the "base_" methods to the klass
		for (property in klass.baseclass.prototype) {
		
			// has this method been overridden?
			if (definition[property]) {
			
				// create accessor
				klass.prototype[objx.Class.basePrefix + property] = klass.baseclass.prototype[property];
			
			}
			
		}
	
	}
	
	// extend the class with the definition
	objx.extend(klass.prototype, definition);
	
	// look for special values
	if (objx.provided("objx.event")) {
		
		for (property in klass.prototype) {
		
			if (klass.prototype[property] == objx.event) {
				
				// add the events

				klass.prototype[property] = (function(property) {
					
					var __property = property;
					
					return function() {
						
						// has this event method been 'exploded' yet?
						if (!this["_ev_" + property]) {
							
							// set the event
							objx(this).event(property);
							
							// set the marker
							this["_ev_" + property] = true;
							
						}
						
						// pass on the call
						this[property].apply(this, arguments);
						
					};
				})(property);
				
			}
		}
		
	}
	
    // set the constructor and classType
    klass.prototype.constructor = klass.prototype.classType = klass;
    
    // return the class
	return klass;

};

objx.Class.basePrefix = "base_";

objx.provides("objx.Class");
/*
 *  objx.collect
 *	Collects the return values from a function called for each
 *	item in an array.
 *
 */
objx.requires("objx.each", "objx.collect");


objx.fn.collect = function( func ) {

	var output = [];
	if(typeof(func)=='string') 
	{
		this.each(function(item){
			output.push(item[func]);
		});
	} 
	else 
	{
		this.each(function(item){
			output.push(func.apply(this, [item]));
		});
	}
	
	return objx(output);

};

objx.provides("objx.collect");
/*
 *	append
 *	Appends one thing to another
 *
 */
objx.fn.append = function() {

	if (arguments.length === 1) {

		var 
			app = arguments[0],
			appType = objx.type(app),
			to = this.obj(),
			toType = this.type(),
			error = false
		;
		
		if (appType == "array") {
		
			if (objx.debug) {
				// we require each
				objx.requires("objx.each", "objx.append (" + appType + " to " + toType + ")");
			}
			
			// add each item in the array to the current array
			objx(app).each(objx.bind(function(item){
				this.append(item);
			}, this));
		
		} else {
			
			switch (toType) {
				case "string":
				
					switch (appType) {
						case "string":
						case "number":
						case "boolean":
							
							this.obj(to += app.toString());
							
							break;
						case "function":
							error = true;
							break;
					}
				
					break;
				case "number":
	
					switch (appType) {
					
						case "boolean":
							error = true;
							break;
						case "function":
							error = true;
							break;
						default:
							
							this.obj(to + parseFloat(app));
							
							break;
					}
	
					break;
				case "boolean":
				
					switch (appType) {
						case "number":
						case "function":
							error = true;
							break;
						default:
						
							if (objx.debug) {
								// we require each
								objx.requires("objx.type", "objx.append (" + appType + " to " + toType + ")");
							}
							
							this.obj(to && objx(app).type("boolean").obj());
							
							break;
					}
				
					break;
				case "array":
				
					to.push(app);

					break;
				
				case "function":
				
					if (appType == "function") {
					
						var originalFunction1 = this.obj();
	
	                    this.obj(
	                        (function(){
	                          
	                          var __orig = originalFunction1;
	                          var __new = app;
	                          
	                          return function(){
	                            __orig.apply(this, arguments);
	                            __new.apply(this, arguments);
	                          };
	    
	                        })()
	                    );
					
					} else {

     					var originalFunction2 = this.obj();
	                    
	                    this.obj(
	                             (function(){
	                               
	                               var __orig = originalFunction2;
	                               var __new = app;
	                               
	                               return function() {
	                                 return objx(__orig.apply(this, arguments)).append(__new).obj();
	                               };
	
	                               })()
	                    );
					
					}
					
					break;
			}
			
		}

	} else {
	
		// handle each argument
		objx(arguments).each(

			// use bind to assign the first parameter
			objx.bind(
			
				// function to call .is() for each argument
				function(context, o) {
				
					// capture the 'passed' value
					context.append(o);
					
				}, 
				
				// we dont care about binding context, just arguments
				null, 
				
				// the first argument should be this context
				this)
				
		);
	
	}
	
	if (error === true) {
		objx.error("objx.append doesn't know how to append " + appType + "'s to " + toType + "'s.");
	}
	
	// return this for chaining
	return this;

};

objx.provides("objx.append");
/*
 *  select
 *  Selects items from an array based on the boolean output of a callback function
 */

objx.requires("objx.is", "objx.select");

objx.fn.select = function() {
	
	if (this.is("array")) {
	
		var 
			newList = [],
			obj = this.obj()
		;
	
		for (var i = 0, l = this.size(); i < l; i++) {
			if (arguments[0].apply(this, [obj[i], i]) === true)
				newList.push(obj[i]);
		}
	
	}
	
	return objx(newList);

};

objx.provides("objx.select");
/*
 * 	type
 *  Adds type conversion capabilities to objx(o).type
 */
 
objx.requires("objx.is", "objx.type");

// save the original type getter
objx.fn.getType = objx.fn.type;

objx.fn.type = function() {

	if (arguments.length === 0) {
	
		// return the type of the object
		return this.getType();
		
	} else {
	
		var 
			_obj = this.obj(),
			fromType = typeof _obj,
			toType = arguments[0].toString(),
			i, l
		;
	
		if (fromType === toType) { return this; }
	
		// cast the current object to another
		switch (toType) {
			case "number":
			
				if (!this.is("something")) { this.obj(0); return this; }

				if (fromType == "boolean") {
				
					if (_obj) {
						return objx(1);
					} else {
						return objx(0);
					}
						
				} else {
				
					return objx(parseFloat(_obj));
				
				}
			
				break;
			case "string":
				if (!this.is("something")) { this.obj(""); }
				this.obj(this.obj().toString());
				break;
			case "boolean":
			
				if (!this.is("something")) { this.obj(false); }
			
				switch (fromType) { 
					case "string":
						return objx(_obj === "true");
						break;
					case "number":
						return objx(!(_obj === 0));
						break;
				}
			
				break;
			case "function":
			
				if (fromType != "function") {
					this.obj(
						objx.bind(function(value){
							return value;
						}, null, this.obj())
					);
				}

				break;
			case "array":
			
				switch (fromType) {
					case "string":
					
						var 
							s = this.obj(),
							chars = []
						;
						
						for (i = 0, l = this.size(); i < l; i++) {
							chars.push(s.charAt(i));
						}
						
						// set the chars
						return objx(chars);
					
						break;
					case "number":
					
						var numbers = [];
						
						for (i = 0, l = this.obj(); i < l; i++) {
							numbers.push(i);
						}
						
						return objx(numbers);
					
						break;
					case "boolean":
					
						return objx([this.obj()]);
					
						break;
				}
			
				break;
			default:
				objx.error("type", "type() doesn't know about the type '" + arguments[0] + "'.");
		}
		
		return this;
	
	}
	
};

objx.provides("objx.type");
/*
 *  remove
 *  Removes an item from another
 */

objx.requires("objx.is", "objx.remove")
	.requires("objx.each", "objx.remove")
	.requires("objx.type", "objx.remove");

objx.fn.remove = function() {
	
	if (arguments.length == 1) {
		
		var 
			itemToRemove = arguments[0],
			obj = this.obj()
		;
		
		switch (this.type()) {
			case "array":
				
				var removeAtIndex = -1;
				obj = this.type("array").obj();
				
				this.each(function(item, index){
					
					if (obj[index] == itemToRemove) {
						removeAtIndex = index;
						return false;
					}
					
				});
				
				if (removeAtIndex > -1) {
					obj.splice(removeAtIndex, 1);
				}
				
				break;
			case "string":
				
				itemToRemove = objx(itemToRemove).type("string").obj();
				
				while (obj.indexOf(itemToRemove) > -1) {
					obj = obj.replace(itemToRemove, "");
				}
				
				// save it
				this.obj(obj);
				
				break;
			default:
				
				objx.error("objx.remove", "remove() doesn't know how to remove from " + this.type() + " objects.");
				
				break;
		}
		
	} else {
		
		objx(arguments).each(objx.bind(function(item){
			this.remove(item);
		}, this));
		
	}
	
	return this;
	
};

objx.provides("objx.remove");
objx.fn.removeAt = function(s,e) {
	
	var 
		_obj = this.obj(),
		len = this.size()
	;
	
	var range = objx.indexRange(s,e,len);
	
	switch (this.type()) {
		case "array":
			_obj.splice(range.start, range.end ? (range.end - range.start + 1) : 1);
			break;
		default:
			objx.error("removeAt", "removeAt() doesn't know how to remove items from objects of type " + this.type());
			break;
	}
	
	this.obj(_obj);
	
	return this;

};

objx.provides("objx.removeAt");
/*
 *  join
 *  joins items in an array
 */

objx.requires("objx.each", "objx.join")
	.requires("objx.append", "objx.join")
	.requires("objx.type", "objx.join");

objx.fn.join = function() {

	var 	obj = this.type("array"),
			output = objx(""), 
			len = this.size(), 
			seps = arguments.length, 
			sep = 0;
	
	obj.each(objx.bind(function(args, item, index){
		
		output.append(item);
		
		if (index < (len - 1)) {
			
			if (args[sep]) {
				output.append(args[sep]);
			}
			
			// reset the separator position
			if (++sep == seps) {
				sep = 0;
			}
			
		}
		
	}, this, arguments));
	
	return output;
	
};

objx.provides("objx.join");
/*
 *	porc
 *  Property OR Callback
 *
 *	Internal handler for providing functionality that supports either
 *  selecting by property name, or using a callback function.
 *
 */
objx.requires("objx.each", "objx.corelist");

objx.porc = function(obj, sel, callback) {
	
	if (obj.type() != "array") {
		objx.error("objx.porc", "You can only use 'porc' on arrays.");
	}
	
	var selType = objx.type(sel);
	
	switch (selType) {
		case "string":	
		
			// property
			obj.each(function(item, index){
				callback.call(this, objx.get(item, sel), index, item);
			});
			
			break;
		case "function":
		
			// callback
			obj.each(function(item, index){
				callback.call(this, sel.apply(this, arguments), index, item);
			});
		
			break;
		default:
			objx.error("objx.porc does not know how to use objects of type " + selType + " to select items.  Use a string describing the property to select or a function that returns the value to use.");
			break;
	}
	
};

objx.fn.porc = function(sel, callback) {
	objx.porc(this, sel, callback);
	return this;
};

objx.provides("objx.corelist");
/*
 *  group
 *  Groups items in an array
 */

objx.requires("objx.corelist", "objx.group");

objx.fn.group = function( sel ) {

	// save the grouped data in a new object
	var grouped = {};
	
	this.porc(sel, function(group, index, source) {
		
		// make sure the group name is an array
		if (!grouped[group]) {
			grouped[group] = [];
		}
		
		// add the item to the group array
		grouped[group].push(source);
		
	});
	
	// return the new object
	return objx(grouped);

};

objx.provides("objx.group");
/*
 * objx.equals
 * 
 */
objx.requires("objx.corelist", "objx.equals");

objx.fn.equals = objx.fn.eq = function(sel, value) {
	
	// save the grouped data in a new object
	var selected = [];
	
	this.porc(sel, function(item, index, source) {

		if (item == value) {
			selected.push(source);
		}
		
	});
	
	// return the new object
	return objx(selected);
	
};

objx.provides("objx.equals");
/*
 *  find
 *  Finds the first item in an array where the callback function returns true
 */
objx.requires("objx.each", "objx.find");

objx.fn.find = function(func){

    var foundObj = null;
    
    this.each(function(item){
    
        if (func.apply(this, arguments)){
            foundObj = item;
            return false;
        }
    
    });

    return objx(foundObj);

};

objx.provides("objx.find");
var IOMath = {
	
	pad: function(number,pad){
		var intString = "";
		intString += number;
		while (intString.length < pad) {
			intString = "0" + intString;
		}
		return intString;
	}
	
};

objx.provides("IOMath");
/* 
  JQuery Truncate (http://www.reindel.com/truncate/ | https://github.com/gravis/jQuery-Truncate/tree)
  v2.3.1 release
  Tested with jQuery 1.3                                                                            
  Author : Brian Reindel
*/ 

jQuery.fn.truncate = function( max, settings ) {
    settings = jQuery.extend( {
        chars: /\s/,
        trail: [ "...", "" ]
    }, settings );
    var myResults = {};
    var ie = $.browser.msie;
    function fixIE( o ) {
        if ( ie ) {
            o.style.removeAttribute( "filter" );
        }
    }
    var original_max = max;
    return this.each( function() {
        var $this = jQuery(this);
        var myStrOrig = $this.html().replace( /\r\n/gim, "" );
        var myStr = myStrOrig;
        var myRegEx = /<\/?[^<>]*\/?>/gim;
        var myRegExArray;
        var myRegExHash = {};
        var myResultsKey = $("*").index( this );     
        while ( ( myRegExArray = myRegEx.exec( myStr ) ) != null ) {
            myRegExHash[ myRegExArray.index ] = myRegExArray[ 0 ];
        }
        myStr = jQuery.trim( myStr.split( myRegEx ).join( "" ) );
        
        if ( myStr.length > original_max ) {
            var c;
            while (( max < myStr.length ) && ( max > 0)) {
                c = myStr.charAt( max );
                if ( c.match( settings.chars ) ) {
                    myStr = myStr.substring( 0, max );
                    break;
                }
                max--;
            }            
            if ( max == 0 ) {
              myStr = myStr.substring( 0, original_max );
            }              
            
            if ( myStrOrig.search( myRegEx ) != -1 ) {
                var endCap = 0;
                for ( eachEl in myRegExHash ) {
                    myStr = [ myStr.substring( 0, eachEl ), myRegExHash[ eachEl ], myStr.substring( eachEl, myStr.length ) ].join( "" );
                    if ( eachEl < myStr.length ) {
                        endCap = myStr.length;
                    }
                }
                $this.html( [ myStr.substring( 0, endCap ), myStr.substring( endCap, myStr.length ).replace( /<(\w+)[^>]*>.*<\/\1>/gim, "" ).replace( /<(br|hr|img|input)[^<>]*\/?>/gim, "" ) ].join( "" ) );
            } else {
                $this.html( myStr );
            }
            myResults[ myResultsKey ] = myStrOrig;
            $this.html( [ "<div class='truncate_less'>", $this.html(), settings.trail[ 0 ], "</div>" ].join( "" ) )
            .find(".truncate_show",this).click( function() {
                if ( $this.find( ".truncate_more" ).length == 0 ) {
                    $this.append( [ "<div class='truncate_more' style='display: none;'>", myResults[ myResultsKey ], settings.trail[ 1 ], "</div>" ].join( "" ) )
                    .find( ".truncate_hide" ).click( function() {
                        $this.find( ".truncate_more" ).css( "background", "#fff" ).fadeOut( "normal", function() {
                            $this.find( ".truncate_less" ).css( "background", "#fff" ).fadeIn( "normal", function() {
                                fixIE( this );
                                $(this).css( "background", "none" );
                            });
                            fixIE( this );
                        });
                        return false;
                    });
                }
                $this.find( ".truncate_less" ).fadeOut( "normal", function() {
                    $this.find( ".truncate_more" ).fadeIn( "normal", function() {
                        fixIE( this );
                    });
                    fixIE( this );
                });
                jQuery(".truncate_show",$this).click( function() {
                    $this.find( ".truncate_less" ).css( "background", "#fff" ).fadeOut( "normal", function() {
                        $this.find( ".truncate_more" ).css( "background", "#fff" ).fadeIn( "normal", function() {
                            fixIE( this );
                            $(this).css( "background", "none" );
                        });
                        fixIE( this );
                    });
                    return false;
                });
                return false;
            });
        }
    });
};
/**
 * jCarousel - Riding carousels with jQuery
 *   http://sorgalla.com/jcarousel/
 *
 * Copyright (c) 2006 Jan Sorgalla (http://sorgalla.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * Built on top of the jQuery library
 *   http://jquery.com
 *
 * Inspired by the "Carousel Component" by Bill Scott
 *   http://billwscott.com/carousel/
 */

(function($) {
    /**
     * Creates a carousel for all matched elements.
     *
     * @example $("#mycarousel").jcarousel();
     * @before <ul id="mycarousel" class="jcarousel-skin-name"><li>First item</li><li>Second item</li></ul>
     * @result
     *
     * <div class="jcarousel-skin-name">
     *   <div class="jcarousel-container">
     *     <div disabled="disabled" class="jcarousel-prev jcarousel-prev-disabled"></div>
     *     <div class="jcarousel-next"></div>
     *     <div class="jcarousel-clip">
     *       <ul class="jcarousel-list">
     *         <li class="jcarousel-item-1">First item</li>
     *         <li class="jcarousel-item-2">Second item</li>
     *       </ul>
     *     </div>
     *   </div>
     * </div>
     *
     * @name jcarousel
     * @type jQuery
     * @param Hash o A set of key/value pairs to set as configuration properties.
     * @cat Plugins/jCarousel
     */
    $.fn.jcarousel = function(o) {
        return this.each(function() {
            new $jc(this, o);
        });
    };

    // Default configuration properties.
    var defaults = {
        vertical: false,
        start: 1,
        offset: 1,
        size: null,
        scroll: 3,
        visible: null,
        animation: 'normal',
        easing: 'swing',
        auto: 0,
        wrap: null,
        initCallback: null,
        reloadCallback: null,
        itemLoadCallback: null,
        itemFirstInCallback: null,
        itemFirstOutCallback: null,
        itemLastInCallback: null,
        itemLastOutCallback: null,
        itemVisibleInCallback: null,
        itemVisibleOutCallback: null,
        buttonNextHTML: '<div></div>',
        buttonPrevHTML: '<div></div>',
        buttonNextEvent: 'click',
        buttonPrevEvent: 'click',
        buttonNextCallback: null,
        buttonPrevCallback: null
    };

    /**
     * The jCarousel object.
     *
     * @constructor
     * @name $.jcarousel
     * @param Object e The element to create the carousel for.
     * @param Hash o A set of key/value pairs to set as configuration properties.
     * @cat Plugins/jCarousel
     */
    $.jcarousel = function(e, o) {
        this.options    = $.extend({}, defaults, o || {});

        this.locked     = false;

        this.container  = null;
        this.clip       = null;
        this.list       = null;
        this.buttonNext = null;
        this.buttonPrev = null;

        this.wh = !this.options.vertical ? 'width' : 'height';
        this.lt = !this.options.vertical ? 'left' : 'top';

        // Extract skin class
        var skin = '', split = e.className.split(' ');

        for (var i = 0; i < split.length; i++) {
            if (split[i].indexOf('jcarousel-skin') != -1) {
                $(e).removeClass(split[i]);
                var skin = split[i];
                break;
            }
        }

        if (e.nodeName == 'UL' || e.nodeName == 'OL') {
            this.list = $(e);
            this.container = this.list.parent();

            if (this.container.hasClass('jcarousel-clip')) {
                if (!this.container.parent().hasClass('jcarousel-container'))
                    this.container = this.container.wrap('<div></div>');

                this.container = this.container.parent();
            } else if (!this.container.hasClass('jcarousel-container'))
                this.container = this.list.wrap('<div></div>').parent();
        } else {
            this.container = $(e);
            this.list = $(e).find('>ul,>ol,div>ul,div>ol');
        }

        if (skin != '' && this.container.parent()[0].className.indexOf('jcarousel-skin') == -1)
        	this.container.wrap('<div class=" '+ skin + '"></div>');

        this.clip = this.list.parent();

        if (!this.clip.length || !this.clip.hasClass('jcarousel-clip'))
            this.clip = this.list.wrap('<div></div>').parent();

        this.buttonPrev = $('.jcarousel-prev', this.container);

        if (this.buttonPrev.size() == 0 && this.options.buttonPrevHTML != null)
            this.buttonPrev = this.clip.before(this.options.buttonPrevHTML).prev();

        this.buttonPrev.addClass(this.className('jcarousel-prev'));

        this.buttonNext = $('.jcarousel-next', this.container);

        if (this.buttonNext.size() == 0 && this.options.buttonNextHTML != null)
            this.buttonNext = this.clip.before(this.options.buttonNextHTML).prev();

        this.buttonNext.addClass(this.className('jcarousel-next'));

        this.clip.addClass(this.className('jcarousel-clip'));
        this.list.addClass(this.className('jcarousel-list'));
        this.container.addClass(this.className('jcarousel-container'));

        var di = this.options.visible != null ? Math.ceil(this.clipping() / this.options.visible) : null;
        var li = this.list.children('li');

        var self = this;

        if (li.size() > 0) {
            var wh = 0, i = this.options.offset;
            li.each(function() {
                self.format(this, i++);
                wh += self.dimension(this, di);
            });

            this.list.css(this.wh, wh + 'px');

            // Only set if not explicitly passed as option
            if (!o || o.size === undefined)
                this.options.size = li.size();
        }

        // For whatever reason, .show() does not work in Safari...
        this.container.css('display', 'block');
        this.buttonNext.css('display', 'block');
        this.buttonPrev.css('display', 'block');

        this.funcNext   = function() { self.next(); };
        this.funcPrev   = function() { self.prev(); };
        this.funcResize = function() { self.reload(); };

        if (this.options.initCallback != null)
            this.options.initCallback(this, 'init');

        if ($.browser.safari) {
            this.buttons(false, false);
            $(window).bind('load', function() { self.setup(); });
        } else
            this.setup();
    };

    // Create shortcut for internal use
    var $jc = $.jcarousel;

    $jc.fn = $jc.prototype = {
        jcarousel: '0.2.3'
    };

    $jc.fn.extend = $jc.extend = $.extend;

    $jc.fn.extend({
        /**
         * Setups the carousel.
         *
         * @name setup
         * @type undefined
         * @cat Plugins/jCarousel
         */
        setup: function() {
            this.first     = null;
            this.last      = null;
            this.prevFirst = null;
            this.prevLast  = null;
            this.animating = false;
            this.timer     = null;
            this.tail      = null;
            this.inTail    = false;

            if (this.locked)
                return;

            this.list.css(this.lt, this.pos(this.options.offset) + 'px');
            var p = this.pos(this.options.start);
            this.prevFirst = this.prevLast = null;
            this.animate(p, false);

            $(window).unbind('resize', this.funcResize).bind('resize', this.funcResize);
        },

        /**
         * Clears the list and resets the carousel.
         *
         * @name reset
         * @type undefined
         * @cat Plugins/jCarousel
         */
        reset: function() {
            this.list.empty();

            this.list.css(this.lt, '0px');
            this.list.css(this.wh, '10px');

            if (this.options.initCallback != null)
                this.options.initCallback(this, 'reset');

            this.setup();
        },

        /**
         * Reloads the carousel and adjusts positions.
         *
         * @name reload
         * @type undefined
         * @cat Plugins/jCarousel
         */
        reload: function() {
            if (this.tail != null && this.inTail)
                this.list.css(this.lt, $jc.intval(this.list.css(this.lt)) + this.tail);

            this.tail   = null;
            this.inTail = false;

            if (this.options.reloadCallback != null)
                this.options.reloadCallback(this);

            if (this.options.visible != null) {
                var self = this;
                var di = Math.ceil(this.clipping() / this.options.visible), wh = 0, lt = 0;
                $('li', this.list).each(function(i) {
                    wh += self.dimension(this, di);
                    if (i + 1 < self.first)
                        lt = wh;
                });

                this.list.css(this.wh, wh + 'px');
                this.list.css(this.lt, -lt + 'px');
            }

            this.scroll(this.first, false);
        },

        /**
         * Locks the carousel.
         *
         * @name lock
         * @type undefined
         * @cat Plugins/jCarousel
         */
        lock: function() {
            this.locked = true;
            this.buttons();
        },

        /**
         * Unlocks the carousel.
         *
         * @name unlock
         * @type undefined
         * @cat Plugins/jCarousel
         */
        unlock: function() {
            this.locked = false;
            this.buttons();
        },

        /**
         * Sets the size of the carousel.
         *
         * @name size
         * @type undefined
         * @param Number s The size of the carousel.
         * @cat Plugins/jCarousel
         */
        size: function(s) {
            if (s != undefined) {
                this.options.size = s;
                if (!this.locked)
                    this.buttons();
            }

            return this.options.size;
        },

        /**
         * Checks whether a list element exists for the given index (or index range).
         *
         * @name get
         * @type bool
         * @param Number i The index of the (first) element.
         * @param Number i2 The index of the last element.
         * @cat Plugins/jCarousel
         */
        has: function(i, i2) {
            if (i2 == undefined || !i2)
                i2 = i;

            if (this.options.size !== null && i2 > this.options.size)
            	i2 = this.options.size;

            for (var j = i; j <= i2; j++) {
                var e = this.get(j);
                if (!e.length || e.hasClass('jcarousel-item-placeholder'))
                    return false;
            }

            return true;
        },

        /**
         * Returns a jQuery object with list element for the given index.
         *
         * @name get
         * @type jQuery
         * @param Number i The index of the element.
         * @cat Plugins/jCarousel
         */
        get: function(i) {
            return $('.jcarousel-item-' + i, this.list);
        },

        /**
         * Adds an element for the given index to the list.
         * If the element already exists, it updates the inner html.
         * Returns the created element as jQuery object.
         *
         * @name add
         * @type jQuery
         * @param Number i The index of the element.
         * @param String s The innerHTML of the element.
         * @cat Plugins/jCarousel
         */
        add: function(i, s) {
            var e = this.get(i), old = 0, add = 0;

            if (e.length == 0) {
                var c, e = this.create(i), j = $jc.intval(i);
                while (c = this.get(--j)) {
                    if (j <= 0 || c.length) {
                        j <= 0 ? this.list.prepend(e) : c.after(e);
                        break;
                    }
                }
            } else
                old = this.dimension(e);

            e.removeClass(this.className('jcarousel-item-placeholder'));
            typeof s == 'string' ? e.html(s) : e.empty().append(s);

            var di = this.options.visible != null ? Math.ceil(this.clipping() / this.options.visible) : null;
            var wh = this.dimension(e, di) - old;

            if (i > 0 && i < this.first)
                this.list.css(this.lt, $jc.intval(this.list.css(this.lt)) - wh + 'px');

            this.list.css(this.wh, $jc.intval(this.list.css(this.wh)) + wh + 'px');

            return e;
        },

        /**
         * Removes an element for the given index from the list.
         *
         * @name remove
         * @type undefined
         * @param Number i The index of the element.
         * @cat Plugins/jCarousel
         */
        remove: function(i) {
            var e = this.get(i);

            // Check if item exists and is not currently visible
            if (!e.length || (i >= this.first && i <= this.last))
                return;

            var d = this.dimension(e);

            if (i < this.first)
                this.list.css(this.lt, $jc.intval(this.list.css(this.lt)) + d + 'px');

            e.remove();

            this.list.css(this.wh, $jc.intval(this.list.css(this.wh)) - d + 'px');
        },

        /**
         * Moves the carousel forwards.
         *
         * @name next
         * @type undefined
         * @cat Plugins/jCarousel
         */
        next: function() {
            this.stopAuto();

            if (this.tail != null && !this.inTail)
                this.scrollTail(false);
            else
                this.scroll(((this.options.wrap == 'both' || this.options.wrap == 'last') && this.options.size != null && this.last == this.options.size) ? 1 : this.first + this.options.scroll);
        },

        /**
         * Moves the carousel backwards.
         *
         * @name prev
         * @type undefined
         * @cat Plugins/jCarousel
         */
        prev: function() {
            this.stopAuto();

            if (this.tail != null && this.inTail)
                this.scrollTail(true);
            else
                this.scroll(((this.options.wrap == 'both' || this.options.wrap == 'first') && this.options.size != null && this.first == 1) ? this.options.size : this.first - this.options.scroll);
        },

        /**
         * Scrolls the tail of the carousel.
         *
         * @name scrollTail
         * @type undefined
         * @param Bool b Whether scroll the tail back or forward.
         * @cat Plugins/jCarousel
         */
        scrollTail: function(b) {
            if (this.locked || this.animating || !this.tail)
                return;

            var pos  = $jc.intval(this.list.css(this.lt));

            !b ? pos -= this.tail : pos += this.tail;
            this.inTail = !b;

            // Save for callbacks
            this.prevFirst = this.first;
            this.prevLast  = this.last;

            this.animate(pos);
        },

        /**
         * Scrolls the carousel to a certain position.
         *
         * @name scroll
         * @type undefined
         * @param Number i The index of the element to scoll to.
         * @param Bool a Flag indicating whether to perform animation.
         * @cat Plugins/jCarousel
         */
        scroll: function(i, a) {
            if (this.locked || this.animating)
                return;

            this.animate(this.pos(i), a);
        },

        /**
         * Prepares the carousel and return the position for a certian index.
         *
         * @name pos
         * @type Number
         * @param Number i The index of the element to scoll to.
         * @cat Plugins/jCarousel
         */
        pos: function(i) {
            if (this.locked || this.animating)
                return;

            i = $jc.intval(i);
            if (this.options.wrap != 'circular')
                i = i < 1 ? 1 : (this.options.size && i > this.options.size ? this.options.size : i);

            var back = this.first > i;
            var pos  = $jc.intval(this.list.css(this.lt));

            // Create placeholders, new list width/height
            // and new list position
            var f = this.options.wrap != 'circular' && this.first <= 1 ? 1 : this.first;
            var c = back ? this.get(f) : this.get(this.last);
            var j = back ? f : f - 1;
            var e = null, l = 0, p = false, d = 0;

            while (back ? --j >= i : ++j < i) {
                e = this.get(j);
                p = !e.length;
                if (e.length == 0) {
                    e = this.create(j).addClass(this.className('jcarousel-item-placeholder'));
                    c[back ? 'before' : 'after' ](e);
                }

                c = e;
                d = this.dimension(e);

                if (p)
                    l += d;

                if (this.first != null && (this.options.wrap == 'circular' || (j >= 1 && (this.options.size == null || j <= this.options.size))))
                    pos = back ? pos + d : pos - d;
            }

            // Calculate visible items
            var clipping = this.clipping();
            var cache = [];
            var visible = 0, j = i, v = 0;
            var c = this.get(i - 1);

            while (++visible) {
                e = this.get(j);
                p = !e.length;
                if (e.length == 0) {
                    e = this.create(j).addClass(this.className('jcarousel-item-placeholder'));
                    // This should only happen on a next scroll
                    c.length == 0 ? this.list.prepend(e) : c[back ? 'before' : 'after' ](e);
                }

                c = e;
                var d = this.dimension(e);
                if (d == 0) {
                    alert('jCarousel: No width/height set for items. This will cause an infinite loop. Aborting...');
                    return 0;
                }

                if (this.options.wrap != 'circular' && this.options.size !== null && j > this.options.size)
                    cache.push(e);
                else if (p)
                    l += d;

                v += d;

                if (v >= clipping)
                    break;

                j++;
            }

             // Remove out-of-range placeholders
            for (var x = 0; x < cache.length; x++)
                cache[x].remove();

            // Resize list
            if (l > 0) {
                this.list.css(this.wh, this.dimension(this.list) + l + 'px');

                if (back) {
                    pos -= l;
                    this.list.css(this.lt, $jc.intval(this.list.css(this.lt)) - l + 'px');
                }
            }

            // Calculate first and last item
            var last = i + visible - 1;
            if (this.options.wrap != 'circular' && this.options.size && last > this.options.size)
                last = this.options.size;

            if (j > last) {
                visible = 0, j = last, v = 0;
                while (++visible) {
                    var e = this.get(j--);
                    if (!e.length)
                        break;
                    v += this.dimension(e);
                    if (v >= clipping)
                        break;
                }
            }

            var first = last - visible + 1;
            if (this.options.wrap != 'circular' && first < 1)
                first = 1;

            if (this.inTail && back) {
                pos += this.tail;
                this.inTail = false;
            }

            this.tail = null;
            if (this.options.wrap != 'circular' && last == this.options.size && (last - visible + 1) >= 1) {
                var m = $jc.margin(this.get(last), !this.options.vertical ? 'marginRight' : 'marginBottom');
                if ((v - m) > clipping)
                    this.tail = v - clipping - m;
            }

            // Adjust position
            while (i-- > first)
                pos += this.dimension(this.get(i));

            // Save visible item range
            this.prevFirst = this.first;
            this.prevLast  = this.last;
            this.first     = first;
            this.last      = last;

            return pos;
        },

        /**
         * Animates the carousel to a certain position.
         *
         * @name animate
         * @type undefined
         * @param mixed p Position to scroll to.
         * @param Bool a Flag indicating whether to perform animation.
         * @cat Plugins/jCarousel
         */
        animate: function(p, a) {
            if (this.locked || this.animating)
                return;

            this.animating = true;

            var self = this;
            var scrolled = function() {
                self.animating = false;

                if (p == 0)
                    self.list.css(self.lt,  0);

                if (self.options.wrap == 'both' || self.options.wrap == 'last' || self.options.size == null || self.last < self.options.size)
                    self.startAuto();

                self.buttons();
                self.notify('onAfterAnimation');
            };

            this.notify('onBeforeAnimation');

            // Animate
            if (!this.options.animation || a == false) {
                this.list.css(this.lt, p + 'px');
                scrolled();
            } else {
                var o = !this.options.vertical ? {'left': p} : {'top': p};
                this.list.animate(o, this.options.animation, this.options.easing, scrolled);
            }
        },

        /**
         * Starts autoscrolling.
         *
         * @name auto
         * @type undefined
         * @param Number s Seconds to periodically autoscroll the content.
         * @cat Plugins/jCarousel
         */
        startAuto: function(s) {
            if (s != undefined)
                this.options.auto = s;

            if (this.options.auto == 0)
                return this.stopAuto();

            if (this.timer != null)
                return;

            var self = this;
            this.timer = setTimeout(function() { self.next(); }, this.options.auto * 1000);
        },

        /**
         * Stops autoscrolling.
         *
         * @name stopAuto
         * @type undefined
         * @cat Plugins/jCarousel
         */
        stopAuto: function() {
            if (this.timer == null)
                return;

            clearTimeout(this.timer);
            this.timer = null;
        },

        /**
         * Sets the states of the prev/next buttons.
         *
         * @name buttons
         * @type undefined
         * @cat Plugins/jCarousel
         */
        buttons: function(n, p) {
            if (n == undefined || n == null) {
                var n = !this.locked && this.options.size !== 0 && ((this.options.wrap && this.options.wrap != 'first') || this.options.size == null || this.last < this.options.size);
                if (!this.locked && (!this.options.wrap || this.options.wrap == 'first') && this.options.size != null && this.last >= this.options.size)
                    n = this.tail != null && !this.inTail;
            }

            if (p == undefined || p == null) {
                var p = !this.locked && this.options.size !== 0 && ((this.options.wrap && this.options.wrap != 'last') || this.first > 1);
                if (!this.locked && (!this.options.wrap || this.options.wrap == 'last') && this.options.size != null && this.first == 1)
                    p = this.tail != null && this.inTail;
            }

            var self = this;

            this.buttonNext[n ? 'bind' : 'unbind'](this.options.buttonNextEvent, this.funcNext)[n ? 'removeClass' : 'addClass'](this.className('jcarousel-next-disabled')).attr('disabled', n ? false : true);
            this.buttonPrev[p ? 'bind' : 'unbind'](this.options.buttonPrevEvent, this.funcPrev)[p ? 'removeClass' : 'addClass'](this.className('jcarousel-prev-disabled')).attr('disabled', p ? false : true);

            if (this.buttonNext.length > 0 && (this.buttonNext[0].jcarouselstate == undefined || this.buttonNext[0].jcarouselstate != n) && this.options.buttonNextCallback != null) {
                this.buttonNext.each(function() { self.options.buttonNextCallback(self, this, n); });
                this.buttonNext[0].jcarouselstate = n;
            }

            if (this.buttonPrev.length > 0 && (this.buttonPrev[0].jcarouselstate == undefined || this.buttonPrev[0].jcarouselstate != p) && this.options.buttonPrevCallback != null) {
                this.buttonPrev.each(function() { self.options.buttonPrevCallback(self, this, p); });
                this.buttonPrev[0].jcarouselstate = p;
            }
        },

        notify: function(evt) {
            var state = this.prevFirst == null ? 'init' : (this.prevFirst < this.first ? 'next' : 'prev');

            // Load items
            this.callback('itemLoadCallback', evt, state);

            if (this.prevFirst !== this.first) {
                this.callback('itemFirstInCallback', evt, state, this.first);
                this.callback('itemFirstOutCallback', evt, state, this.prevFirst);
            }

            if (this.prevLast !== this.last) {
                this.callback('itemLastInCallback', evt, state, this.last);
                this.callback('itemLastOutCallback', evt, state, this.prevLast);
            }

            this.callback('itemVisibleInCallback', evt, state, this.first, this.last, this.prevFirst, this.prevLast);
            this.callback('itemVisibleOutCallback', evt, state, this.prevFirst, this.prevLast, this.first, this.last);
        },

        callback: function(cb, evt, state, i1, i2, i3, i4) {
            if (this.options[cb] == undefined || (typeof this.options[cb] != 'object' && evt != 'onAfterAnimation'))
                return;

            var callback = typeof this.options[cb] == 'object' ? this.options[cb][evt] : this.options[cb];

            if (!$.isFunction(callback))
                return;

            var self = this;

            if (i1 === undefined)
                callback(self, state, evt);
            else if (i2 === undefined)
                this.get(i1).each(function() { callback(self, this, i1, state, evt); });
            else {
                for (var i = i1; i <= i2; i++)
                    if (i !== null && !(i >= i3 && i <= i4))
                        this.get(i).each(function() { callback(self, this, i, state, evt); });
            }
        },

        create: function(i) {
            return this.format('<li></li>', i);
        },

        format: function(e, i) {
            var $e = $(e).addClass(this.className('jcarousel-item')).addClass(this.className('jcarousel-item-' + i));
            $e.attr('jcarouselindex', i);
            return $e;
        },

        className: function(c) {
            return c + ' ' + c + (!this.options.vertical ? '-horizontal' : '-vertical');
        },

        dimension: function(e, d) {
            var el = e.jquery != undefined ? e[0] : e;

            var old = !this.options.vertical ?
                el.offsetWidth + $jc.margin(el, 'marginLeft') + $jc.margin(el, 'marginRight') :
                el.offsetHeight + $jc.margin(el, 'marginTop') + $jc.margin(el, 'marginBottom');

            if (d == undefined || old == d)
                return old;

            var w = !this.options.vertical ?
                d - $jc.margin(el, 'marginLeft') - $jc.margin(el, 'marginRight') :
                d - $jc.margin(el, 'marginTop') - $jc.margin(el, 'marginBottom');

            $(el).css(this.wh, w + 'px');

            return this.dimension(el);
        },

        clipping: function() {
            return !this.options.vertical ?
                this.clip[0].offsetWidth - $jc.intval(this.clip.css('borderLeftWidth')) - $jc.intval(this.clip.css('borderRightWidth')) :
                this.clip[0].offsetHeight - $jc.intval(this.clip.css('borderTopWidth')) - $jc.intval(this.clip.css('borderBottomWidth'));
        },

        index: function(i, s) {
            if (s == undefined)
                s = this.options.size;

            return Math.round((((i-1) / s) - Math.floor((i-1) / s)) * s) + 1;
        }
    });

    $jc.extend({
        /**
         * Gets/Sets the global default configuration properties.
         *
         * @name defaults
         * @descr Gets/Sets the global default configuration properties.
         * @type Hash
         * @param Hash d A set of key/value pairs to set as configuration properties.
         * @cat Plugins/jCarousel
         */
        defaults: function(d) {
            return $.extend(defaults, d || {});
        },

        margin: function(e, p) {
            if (!e)
                return 0;

            var el = e.jquery != undefined ? e[0] : e;

            if (p == 'marginRight' && $.browser.safari) {
                var old = {'display': 'block', 'float': 'none', 'width': 'auto'}, oWidth, oWidth2;

                $.swap(el, old, function() { oWidth = el.offsetWidth; });

                old['marginRight'] = 0;
                $.swap(el, old, function() { oWidth2 = el.offsetWidth; });

                return oWidth2 - oWidth;
            }

            return $jc.intval($.css(el, p));
        },

        intval: function(v) {
            v = parseInt(v);
            return isNaN(v) ? 0 : v;
        }
    });

})(jQuery);
objx.requires("IOMath", "jquery.editable");

(function($){
/*
 * Editable 1.3.4-beta
 *
 * Copyright (c) 2009 Arash Karimzadeh (arashkarimzadeh.com)
 * Licensed under the MIT (MIT-LICENSE.txt)
 * http://www.opensource.org/licenses/mit-license.php
 *
 * Date: Mar 04 2009
 */
$.fn.editable = function(options){
	var defaults = {
		onEdit: null,
		onSubmit: null,
		onCancel: null,
		onClear: null,
		editClass: null,
		submit: null,
		cancel: null,
		result: null,
		clearBy: null,
		className: 'editable',
		guideText: 'Enter a value',
		type: 'text', //text, textarea or select
		submitBy: 'blur', //blur,change,dblclick,click
		editBy: 'click',
		options: null
	}
	if(options=='disable')
		return this.unbind(this.data('editable.options').editBy,this.data('editable.options').toEditable);
	if(options=='enable')
		return this.bind(this.data('editable.options').editBy,this.data('editable.options').toEditable);
	if(options=='destroy') {
	
		if (!this.data("editable.options"))
			return this;

		return  this.unbind(this.data('editable.options').editBy,this.data('editable.options').toEditable)
					.data('editable.previous',null)
					.data('editable.current',null)
					.data('editable.options',null);
	}
	
	var options = $.extend(defaults, options);
	
	var addGuideText = function(el){
		el.addClass("guide-text").html(options.guideText);
	}
	var checkEmpty = function(el){
		if(el.text().length == 0){
			addGuideText(el);
		} else {
			el.removeClass("guide-text");
		}
	}
	if (options.guideText){
		if (options.type=="text" || options.type=="textarea" || options.type=="time" || options.type=="date"){
			checkEmpty($(this));
		}
	}
	
	if (options.className){
		$(this).addClass(options.className);
	}
	
	options.toEditable = function(){
		$this = $(this);
		if ($this.hasClass("guide-text")){
			$this.html("").removeClass("guide-text");
		}
		$this.data('editable.current',$this.html());
		opts = $this.data('editable.options');
		
		$this.bind('keydown',function(event){
			if (event.keyCode == 13 && opts.type != "textarea"){$this.unbind('keydown');opts.toNonEditable($(this),true)}
			else if(event.keyCode == 27){$this.unbind('keydown');opts.toNonEditable($(this),false)}
		});
		
		$.editableFactory[opts.type].toEditable($this.empty(),opts);
		
		$("<div/>").addClass("options").hide().appendTo($this);
		// Configure events,styles for changed content
		$this.data('editable.previous',$this.data('editable.current'))
			 .children()
				 .focus()
				 .addClass(opts.editClass);
		// Submit Event
		if(opts.submit){
			$('<a/>').appendTo($this.children(".options").show())
						.html(opts.submit)
						.one('mousedown',function(){opts.toNonEditable($this,true)})
		}else if (opts.submitBy){
			setTimeout(function(){
				$this.one(opts.submitBy,function(){opts.toNonEditable($(this),true)})
					 .children()
					 	.one(opts.submitBy,function(){opts.toNonEditable($this,true)});
			}, 1);
		}
		// Cancel Event
		if(opts.cancel)
			$('<a/>').appendTo($this.children(".options").show())
						.html(opts.cancel)
						.one('mousedown',function(){opts.toNonEditable($this,false)});
		
		if(opts.clearBy)
			$(opts.clearBy).one("click", function(){
				$this.data('editable.current','');
				opts.toNonEditable($this,false);
				if (opts.onClear)
					opts.onClear();
			});
		
			
		// Call User Function
		if($.isFunction(opts.onEdit))
			opts.onEdit.apply(	$this,
									[{
										current:$this.data('editable.current'),
										previous:$this.data('editable.previous')
									}]
								);
	}
	options.toNonEditable = function($this,change){
		opts = $this.data('editable.options');
		// Configure events,styles for changed content
		$this.one(opts.editBy,opts.toEditable)
			 .data( 'editable.current',
				    change 
						?$.editableFactory[opts.type].getValue($this,opts)
						:$this.data('editable.current')
					).html(
					    opts.type=='password'
					   		?'*****'
							:$this.data('editable.current')
					).removeClass("guide-text");
		if (opts.guideText && $this.data('editable.current').length == 0){
			$this.html(opts.guideText).addClass("guide-text")
		} 
		// Call User Function
		var func = null;
		if($.isFunction(opts.onSubmit)&&change==true)
			func = opts.onSubmit;
		else if($.isFunction(opts.onCancel)&&change==false)
			func = opts.onCancel;
		if(func!=null)
			func.apply($this,
						[{
							current:$this.data('editable.current'),
							previous:$this.data('editable.previous')
						}]
					);
	}
	this.data('editable.options',options);
	return this.one(options.editBy,options.toEditable);
}
$.editableFactory = {
	'text': {
		toEditable: function($this,options){
			$('<input/>').appendTo($this)
						 .val($this.data('editable.current'))
						 .select()
						 .focus();
		},
		getValue: function($this,options){
			return $this.children().val();
		}
	},
	'password': {
		toEditable: function($this,options){
			$this.data('editable.current',$this.data('editable.password'));
			$this.data('editable.previous',$this.data('editable.password'));
			$('<input type="password"/>').appendTo($this)
										 .val($this.data('editable.current'));
		},
		getValue: function($this,options){
			$this.data('editable.password',$this.children().val());
			return $this.children().val();
		}
	},
	'textarea': {
		toEditable: function($this,options){
			$('<textarea/>').appendTo($this)
							.val($this.data('editable.current'))
							.focus();
		},
		getValue: function($this,options){
			return $this.children().val();
		}
	},
	'select': {
		toEditable: function($this,options){
			$select = $('<select/>').appendTo($this);
			$.each( options.options,
					function(key,value){
						$('<option/>').appendTo($select)
									.html(value)
									.attr('value',key);
					}
				   )
			$select.children().each(
				function(){
					var opt = $(this);
					if(opt.text()==$this.data('editable.current'))
						return opt.attr('selected', 'selected').text();
				}
			)
		},
		getValue: function($this,options){
			var item = null;
			$('select', $this).children().each(
				function(){
					if($(this).attr('selected'))
						return item = $(this).text();
				}
			)
			return item;
		}
	},
	'time': {
		toEditable: function($this,option){
			if (lastEditableTimeTimeout){
				clearTimeout(lastEditableTimeTimeout);
			}
			if (lastEditableTimeEl && $this[0] != lastEditableTimeEl[0]){
				lastEditableTimeEl.find(".hour").blur();
			}
			$this.data('timeElHasFocus', false);
			opts.submitBy = null;
			opts.clearBy.click(function(){
			 $this.data('timeElHasFocus', true);	
			});
			var hour = $("<select/>").addClass("hour");
			var minute = $("<select/>").addClass("minute");
			hour
				.bind("focus", function(){
					setTimeout(function(){$this.data('timeElHasFocus', true);},50);
				})
				.bind("blur", function(){
					$this.data('timeElHasFocus', false);
					lastEditableTimeTimeout = setTimeout(function(){
						if ($this.data('timeElHasFocus') == false){
							opts.toNonEditable($this,true)
						}
					}, 100)
				});	
			minute
				.bind("focus", function(){
					setTimeout(function(){$this.data('timeElHasFocus', true);},50);
				})
				.bind("blur", function(){
					$this.data('timeElHasFocus', false);
					lastEditableTimeTimeout = setTimeout(function(){
						if ($this.data('timeElHasFocus') == false){
							opts.toNonEditable($this,true)
						}
					}, 100)
				});
			// FIX ME - eq(0) eq(1) doesn't allow for future changes
			var currentHour = $($this.data('editable.current')).eq(0).text();
			var currentMinute = $($this.data('editable.current')).eq(2).text();
			for (var i=0; i<24; i++){
				var hourOption = $("<option/>").html(IOMath.pad(i,2)).appendTo(hour);
				if (currentHour == i){
					hourOption.attr("selected","selected");
				}
			}
			for (var i=0; i<60; i=i+5){
				var minuteOption = $("<option/>").html(IOMath.pad(i,2)).appendTo(minute);
				if (currentMinute == i){
					minuteOption.attr("selected","selected");
				}
			}
			$this.append(hour,minute);
			lastEditableTimeEl = $this;
		},
		getValue: function($this,options){
			return $this.find(".hour").val() + $this.find(".minute").val(); 
		}
	},
	'date': {
		toEditable: function($this,option){
			var day = $("<select/>").addClass("day");
			var month = $("<select/>").addClass("month");
			var year = $("<select/>").addClass("year");
			var currentText = $this.data('editable.current') || IODateTime.toNiceDate(new Date());
			var currentData = IODateTime.fromNiceDateToIODate(currentText);
			var currentDay = currentData.day;
			var currentMonth = currentData.month;
			var currentYear = currentData.year;
			for (var i=1; i<=31; i++){
				var dayOption = $("<option/>").html(IOMath.pad(i,2)).appendTo(day);
				if (currentDay == i){
					dayOption.attr("selected","selected");
				}
			}
			for (var i=0; i<IODateTime.months.length; i++){
				var monthOption = $("<option value=" + i + "/>").html(IODateTime.months[i]).appendTo(month);
				if (currentMonth == i){
					monthOption.attr("selected","selected");
				}
			}
			var thisYear = new Date().getFullYear();
			for (var i=thisYear; i<=thisYear+1; i++){
				var yearOption = $("<option/>").html(i).appendTo(year);
				if (currentYear == i){
					yearOption.attr("selected","selected");
				}
			}
			$this.append(day,month,year);
		},
		getValue: function($this,options){
			var d = new Date();
			d.setFullYear(parseInt($this.find(".year").val(), 10), parseInt($this.find(".month").val(), 10), parseInt($this.find(".day").val(), 10));
			return IODateTime.toNiceDate(d); 
		}
	}
}
})(jQuery);

var lastEditableTimeEl = null;
var lastEditableTimeTimeout = null;

objx.provides("jquery.editable");
/*
Usage 1: define the default prefix by using an object with the property prefix as a parameter which contains a string value; {prefix: 'id'}
Usage 2: call the function jQuery.uuid() with a string parameter p to be used as a prefix to generate a random uuid;
Usage 3: call the function jQuery.uuid() with no parameters to generate a uuid with the default prefix; defaul prefix: '' (empty string)
*/

/*
Generate fragment of random numbers
*/
jQuery._uuid_default_prefix = '';
jQuery._uuidlet = function () {
	return(((1+Math.random())*0x10000)|0).toString(16).substring(1);
};
/*
Generates random uuid
*/
jQuery.uuid = function (p) {
	if (typeof(p) == 'object' && typeof(p.prefix) == 'string') {
		jQuery._uuid_default_prefix = p.prefix;
	} else {
		p = p || jQuery._uuid_default_prefix || '';
		return(p+jQuery._uuidlet()+jQuery._uuidlet()+"-"+jQuery._uuidlet()+"-"+jQuery._uuidlet()+"-"+jQuery._uuidlet()+"-"+jQuery._uuidlet()+jQuery._uuidlet()+jQuery._uuidlet());
	};
};

objx.provides("jquery.uuid");
/*
 * jQuery validation plug-in 1.5.5
 *
 * http://bassistance.de/jquery-plugins/jquery-plugin-validation/
 * http://docs.jquery.com/Plugins/Validation
 *
 * Copyright (c) 2006 - 2008 Jörn Zaefferer
 *
 * $Id: jquery.validate.js 6403 2009-06-17 14:27:16Z joern.zaefferer $
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 */
(function($){$.extend($.fn,{validate:function(options){if(!this.length){options&&options.debug&&window.console&&console.warn("nothing selected, can't validate, returning nothing");return;}var validator=$.data(this[0],'validator');if(validator){return validator;}validator=new $.validator(options,this[0]);$.data(this[0],'validator',validator);if(validator.settings.onsubmit){this.find("input, button").filter(".cancel").click(function(){validator.cancelSubmit=true;});if(validator.settings.submitHandler){this.find("input, button").filter(":submit").click(function(){validator.submitButton=this;});}this.submit(function(event){if(validator.settings.debug)event.preventDefault();function handle(){if(validator.settings.submitHandler){if(validator.submitButton){var hidden=$("<input type='hidden'/>").attr("name",validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm);}validator.settings.submitHandler.call(validator,validator.currentForm);if(validator.submitButton){hidden.remove();}return false;}return true;}if(validator.cancelSubmit){validator.cancelSubmit=false;return handle();}if(validator.form()){if(validator.pendingRequest){validator.formSubmitted=true;return false;}return handle();}else{validator.focusInvalid();return false;}});}return validator;},valid:function(){if($(this[0]).is('form')){return this.validate().form();}else{var valid=true;var validator=$(this[0].form).validate();this.each(function(){valid&=validator.element(this);});return valid;}},removeAttrs:function(attributes){var result={},$element=this;$.each(attributes.split(/\s/),function(index,value){result[value]=$element.attr(value);$element.removeAttr(value);});return result;},rules:function(command,argument){var element=this[0];if(command){var settings=$.data(element.form,'validator').settings;var staticRules=settings.rules;var existingRules=$.validator.staticRules(element);switch(command){case"add":$.extend(existingRules,$.validator.normalizeRule(argument));staticRules[element.name]=existingRules;if(argument.messages)settings.messages[element.name]=$.extend(settings.messages[element.name],argument.messages);break;case"remove":if(!argument){delete staticRules[element.name];return existingRules;}var filtered={};$.each(argument.split(/\s/),function(index,method){filtered[method]=existingRules[method];delete existingRules[method];});return filtered;}}var data=$.validator.normalizeRules($.extend({},$.validator.metadataRules(element),$.validator.classRules(element),$.validator.attributeRules(element),$.validator.staticRules(element)),element);if(data.required){var param=data.required;delete data.required;data=$.extend({required:param},data);}return data;}});$.extend($.expr[":"],{blank:function(a){return!$.trim(a.value);},filled:function(a){return!!$.trim(a.value);},unchecked:function(a){return!a.checked;}});$.validator=function(options,form){this.settings=$.extend({},$.validator.defaults,options);this.currentForm=form;this.init();};$.validator.format=function(source,params){if(arguments.length==1)return function(){var args=$.makeArray(arguments);args.unshift(source);return $.validator.format.apply(this,args);};if(arguments.length>2&&params.constructor!=Array){params=$.makeArray(arguments).slice(1);}if(params.constructor!=Array){params=[params];}$.each(params,function(i,n){source=source.replace(new RegExp("\\{"+i+"\\}","g"),n);});return source;};$.extend($.validator,{defaults:{messages:{},groups:{},rules:{},errorClass:"error",validClass:"valid",errorElement:"label",focusInvalid:true,errorContainer:$([]),errorLabelContainer:$([]),onsubmit:true,ignore:[],ignoreTitle:false,onfocusin:function(element){this.lastActive=element;if(this.settings.focusCleanup&&!this.blockFocusCleanup){this.settings.unhighlight&&this.settings.unhighlight.call(this,element,this.settings.errorClass,this.settings.validClass);this.errorsFor(element).hide();}},onfocusout:function(element){if(!this.checkable(element)&&(element.name in this.submitted||!this.optional(element))){this.element(element);}},onkeyup:function(element){if(element.name in this.submitted||element==this.lastElement){this.element(element);}},onclick:function(element){if(element.name in this.submitted)this.element(element);},highlight:function(element,errorClass,validClass){$(element).addClass(errorClass).removeClass(validClass);},unhighlight:function(element,errorClass,validClass){$(element).removeClass(errorClass).addClass(validClass);}},setDefaults:function(settings){$.extend($.validator.defaults,settings);},messages:{required:"This field is required.",remote:"Please fix this field.",email:"Please enter a valid email address.",url:"Please enter a valid URL.",date:"Please enter a valid date.",dateISO:"Please enter a valid date (ISO).",dateDE:"Bitte geben Sie ein gültiges Datum ein.",number:"Please enter a valid number.",numberDE:"Bitte geben Sie eine Nummer ein.",digits:"Please enter only digits",creditcard:"Please enter a valid credit card number.",equalTo:"Please enter the same value again.",accept:"Please enter a value with a valid extension.",maxlength:$.validator.format("Please enter no more than {0} characters."),minlength:$.validator.format("Please enter at least {0} characters."),rangelength:$.validator.format("Please enter a value between {0} and {1} characters long."),range:$.validator.format("Please enter a value between {0} and {1}."),max:$.validator.format("Please enter a value less than or equal to {0}."),min:$.validator.format("Please enter a value greater than or equal to {0}.")},autoCreateRanges:false,prototype:{init:function(){this.labelContainer=$(this.settings.errorLabelContainer);this.errorContext=this.labelContainer.length&&this.labelContainer||$(this.currentForm);this.containers=$(this.settings.errorContainer).add(this.settings.errorLabelContainer);this.submitted={};this.valueCache={};this.pendingRequest=0;this.pending={};this.invalid={};this.reset();var groups=(this.groups={});$.each(this.settings.groups,function(key,value){$.each(value.split(/\s/),function(index,name){groups[name]=key;});});var rules=this.settings.rules;$.each(rules,function(key,value){rules[key]=$.validator.normalizeRule(value);});function delegate(event){var validator=$.data(this[0].form,"validator");validator.settings["on"+event.type]&&validator.settings["on"+event.type].call(validator,this[0]);}$(this.currentForm).delegate("focusin focusout keyup",":text, :password, :file, select, textarea",delegate).delegate("click",":radio, :checkbox",delegate);if(this.settings.invalidHandler)$(this.currentForm).bind("invalid-form.validate",this.settings.invalidHandler);},form:function(){this.checkForm();$.extend(this.submitted,this.errorMap);this.invalid=$.extend({},this.errorMap);if(!this.valid())$(this.currentForm).triggerHandler("invalid-form",[this]);this.showErrors();return this.valid();},checkForm:function(){this.prepareForm();for(var i=0,elements=(this.currentElements=this.elements());elements[i];i++){this.check(elements[i]);}return this.valid();},element:function(element){element=this.clean(element);this.lastElement=element;this.prepareElement(element);this.currentElements=$(element);var result=this.check(element);if(result){delete this.invalid[element.name];}else{this.invalid[element.name]=true;}if(!this.numberOfInvalids()){this.toHide=this.toHide.add(this.containers);}this.showErrors();return result;},showErrors:function(errors){if(errors){$.extend(this.errorMap,errors);this.errorList=[];for(var name in errors){this.errorList.push({message:errors[name],element:this.findByName(name)[0]});}this.successList=$.grep(this.successList,function(element){return!(element.name in errors);});}this.settings.showErrors?this.settings.showErrors.call(this,this.errorMap,this.errorList):this.defaultShowErrors();},resetForm:function(){if($.fn.resetForm)$(this.currentForm).resetForm();this.submitted={};this.prepareForm();this.hideErrors();this.elements().removeClass(this.settings.errorClass);},numberOfInvalids:function(){return this.objectLength(this.invalid);},objectLength:function(obj){var count=0;for(var i in obj)count++;return count;},hideErrors:function(){this.addWrapper(this.toHide).hide();},valid:function(){return this.size()==0;},size:function(){return this.errorList.length;},focusInvalid:function(){if(this.settings.focusInvalid){try{$(this.findLastActive()||this.errorList.length&&this.errorList[0].element||[]).filter(":visible").focus();}catch(e){}}},findLastActive:function(){var lastActive=this.lastActive;return lastActive&&$.grep(this.errorList,function(n){return n.element.name==lastActive.name;}).length==1&&lastActive;},elements:function(){var validator=this,rulesCache={};return $([]).add(this.currentForm.elements).filter(":input").not(":submit, :reset, :image, [disabled]").not(this.settings.ignore).filter(function(){!this.name&&validator.settings.debug&&window.console&&console.error("%o has no name assigned",this);if(this.name in rulesCache||!validator.objectLength($(this).rules()))return false;rulesCache[this.name]=true;return true;});},clean:function(selector){return $(selector)[0];},errors:function(){return $(this.settings.errorElement+"."+this.settings.errorClass,this.errorContext);},reset:function(){this.successList=[];this.errorList=[];this.errorMap={};this.toShow=$([]);this.toHide=$([]);this.formSubmitted=false;this.currentElements=$([]);},prepareForm:function(){this.reset();this.toHide=this.errors().add(this.containers);},prepareElement:function(element){this.reset();this.toHide=this.errorsFor(element);},check:function(element){element=this.clean(element);if(this.checkable(element)){element=this.findByName(element.name)[0];}var rules=$(element).rules();var dependencyMismatch=false;for(method in rules){var rule={method:method,parameters:rules[method]};try{var result=$.validator.methods[method].call(this,element.value.replace(/\r/g,""),element,rule.parameters);if(result=="dependency-mismatch"){dependencyMismatch=true;continue;}dependencyMismatch=false;if(result=="pending"){this.toHide=this.toHide.not(this.errorsFor(element));return;}if(!result){this.formatAndAdd(element,rule);return false;}}catch(e){this.settings.debug&&window.console&&console.log("exception occured when checking element "+element.id
+", check the '"+rule.method+"' method");throw e;}}if(dependencyMismatch)return;if(this.objectLength(rules))this.successList.push(element);return true;},customMetaMessage:function(element,method){if(!$.metadata)return;var meta=this.settings.meta?$(element).metadata()[this.settings.meta]:$(element).metadata();return meta&&meta.messages&&meta.messages[method];},customMessage:function(name,method){var m=this.settings.messages[name];return m&&(m.constructor==String?m:m[method]);},findDefined:function(){for(var i=0;i<arguments.length;i++){if(arguments[i]!==undefined)return arguments[i];}return undefined;},defaultMessage:function(element,method){return this.findDefined(this.customMessage(element.name,method),this.customMetaMessage(element,method),!this.settings.ignoreTitle&&element.title||undefined,$.validator.messages[method],"<strong>Warning: No message defined for "+element.name+"</strong>");},formatAndAdd:function(element,rule){var message=this.defaultMessage(element,rule.method);if(typeof message=="function")message=message.call(this,rule.parameters,element);this.errorList.push({message:message,element:element});this.errorMap[element.name]=message;this.submitted[element.name]=message;},addWrapper:function(toToggle){if(this.settings.wrapper)toToggle=toToggle.add(toToggle.parent(this.settings.wrapper));return toToggle;},defaultShowErrors:function(){for(var i=0;this.errorList[i];i++){var error=this.errorList[i];this.settings.highlight&&this.settings.highlight.call(this,error.element,this.settings.errorClass,this.settings.validClass);this.showLabel(error.element,error.message);}if(this.errorList.length){this.toShow=this.toShow.add(this.containers);}if(this.settings.success){for(var i=0;this.successList[i];i++){this.showLabel(this.successList[i]);}}if(this.settings.unhighlight){for(var i=0,elements=this.validElements();elements[i];i++){this.settings.unhighlight.call(this,elements[i],this.settings.errorClass,this.settings.validClass);}}this.toHide=this.toHide.not(this.toShow);this.hideErrors();this.addWrapper(this.toShow).show();},validElements:function(){return this.currentElements.not(this.invalidElements());},invalidElements:function(){return $(this.errorList).map(function(){return this.element;});},showLabel:function(element,message){var label=this.errorsFor(element);if(label.length){label.removeClass().addClass(this.settings.errorClass);label.attr("generated")&&label.html(message);}else{label=$("<"+this.settings.errorElement+"/>").attr({"for":this.idOrName(element),generated:true}).addClass(this.settings.errorClass).html(message||"");if(this.settings.wrapper){label=label.hide().show().wrap("<"+this.settings.wrapper+"/>").parent();}if(!this.labelContainer.append(label).length)this.settings.errorPlacement?this.settings.errorPlacement(label,$(element)):label.insertAfter(element);}if(!message&&this.settings.success){label.text("");typeof this.settings.success=="string"?label.addClass(this.settings.success):this.settings.success(label);}this.toShow=this.toShow.add(label);},errorsFor:function(element){return this.errors().filter("[for='"+this.idOrName(element)+"']");},idOrName:function(element){return this.groups[element.name]||(this.checkable(element)?element.name:element.id||element.name);},checkable:function(element){return/radio|checkbox/i.test(element.type);},findByName:function(name){var form=this.currentForm;return $(document.getElementsByName(name)).map(function(index,element){return element.form==form&&element.name==name&&element||null;});},getLength:function(value,element){switch(element.nodeName.toLowerCase()){case'select':return $("option:selected",element).length;case'input':if(this.checkable(element))return this.findByName(element.name).filter(':checked').length;}return value.length;},depend:function(param,element){return this.dependTypes[typeof param]?this.dependTypes[typeof param](param,element):true;},dependTypes:{"boolean":function(param,element){return param;},"string":function(param,element){return!!$(param,element.form).length;},"function":function(param,element){return param(element);}},optional:function(element){return!$.validator.methods.required.call(this,$.trim(element.value),element)&&"dependency-mismatch";},startRequest:function(element){if(!this.pending[element.name]){this.pendingRequest++;this.pending[element.name]=true;}},stopRequest:function(element,valid){this.pendingRequest--;if(this.pendingRequest<0)this.pendingRequest=0;delete this.pending[element.name];if(valid&&this.pendingRequest==0&&this.formSubmitted&&this.form()){$(this.currentForm).submit();}else if(!valid&&this.pendingRequest==0&&this.formSubmitted){$(this.currentForm).triggerHandler("invalid-form",[this]);}},previousValue:function(element){return $.data(element,"previousValue")||$.data(element,"previousValue",previous={old:null,valid:true,message:this.defaultMessage(element,"remote")});}},classRuleSettings:{required:{required:true},email:{email:true},url:{url:true},date:{date:true},dateISO:{dateISO:true},dateDE:{dateDE:true},number:{number:true},numberDE:{numberDE:true},digits:{digits:true},creditcard:{creditcard:true}},addClassRules:function(className,rules){className.constructor==String?this.classRuleSettings[className]=rules:$.extend(this.classRuleSettings,className);},classRules:function(element){var rules={};var classes=$(element).attr('class');classes&&$.each(classes.split(' '),function(){if(this in $.validator.classRuleSettings){$.extend(rules,$.validator.classRuleSettings[this]);}});return rules;},attributeRules:function(element){var rules={};var $element=$(element);for(method in $.validator.methods){var value=$element.attr(method);if(value){rules[method]=value;}}if(rules.maxlength&&/-1|2147483647|524288/.test(rules.maxlength)){delete rules.maxlength;}return rules;},metadataRules:function(element){if(!$.metadata)return{};var meta=$.data(element.form,'validator').settings.meta;return meta?$(element).metadata()[meta]:$(element).metadata();},staticRules:function(element){var rules={};var validator=$.data(element.form,'validator');if(validator.settings.rules){rules=$.validator.normalizeRule(validator.settings.rules[element.name])||{};}return rules;},normalizeRules:function(rules,element){$.each(rules,function(prop,val){if(val===false){delete rules[prop];return;}if(val.param||val.depends){var keepRule=true;switch(typeof val.depends){case"string":keepRule=!!$(val.depends,element.form).length;break;case"function":keepRule=val.depends.call(element,element);break;}if(keepRule){rules[prop]=val.param!==undefined?val.param:true;}else{delete rules[prop];}}});$.each(rules,function(rule,parameter){rules[rule]=$.isFunction(parameter)?parameter(element):parameter;});$.each(['minlength','maxlength','min','max'],function(){if(rules[this]){rules[this]=Number(rules[this]);}});$.each(['rangelength','range'],function(){if(rules[this]){rules[this]=[Number(rules[this][0]),Number(rules[this][1])];}});if($.validator.autoCreateRanges){if(rules.min&&rules.max){rules.range=[rules.min,rules.max];delete rules.min;delete rules.max;}if(rules.minlength&&rules.maxlength){rules.rangelength=[rules.minlength,rules.maxlength];delete rules.minlength;delete rules.maxlength;}}if(rules.messages){delete rules.messages}return rules;},normalizeRule:function(data){if(typeof data=="string"){var transformed={};$.each(data.split(/\s/),function(){transformed[this]=true;});data=transformed;}return data;},addMethod:function(name,method,message){$.validator.methods[name]=method;$.validator.messages[name]=message||$.validator.messages[name];if(method.length<3){$.validator.addClassRules(name,$.validator.normalizeRule(name));}},methods:{required:function(value,element,param){if(!this.depend(param,element))return"dependency-mismatch";switch(element.nodeName.toLowerCase()){case'select':var options=$("option:selected",element);return options.length>0&&(element.type=="select-multiple"||($.browser.msie&&!(options[0].attributes['value'].specified)?options[0].text:options[0].value).length>0);case'input':if(this.checkable(element))return this.getLength(value,element)>0;default:return $.trim(value).length>0;}},remote:function(value,element,param){if(this.optional(element))return"dependency-mismatch";var previous=this.previousValue(element);if(!this.settings.messages[element.name])this.settings.messages[element.name]={};this.settings.messages[element.name].remote=typeof previous.message=="function"?previous.message(value):previous.message;param=typeof param=="string"&&{url:param}||param;if(previous.old!==value){previous.old=value;var validator=this;this.startRequest(element);var data={};data[element.name]=value;$.ajax($.extend(true,{url:param,mode:"abort",port:"validate"+element.name,dataType:"json",data:data,success:function(response){var valid=response===true;if(valid){var submitted=validator.formSubmitted;validator.prepareElement(element);validator.formSubmitted=submitted;validator.successList.push(element);validator.showErrors();}else{var errors={};errors[element.name]=previous.message=response||validator.defaultMessage(element,"remote");validator.showErrors(errors);}previous.valid=valid;validator.stopRequest(element,valid);}},param));return"pending";}else if(this.pending[element.name]){return"pending";}return previous.valid;},minlength:function(value,element,param){return this.optional(element)||this.getLength($.trim(value),element)>=param;},maxlength:function(value,element,param){return this.optional(element)||this.getLength($.trim(value),element)<=param;},rangelength:function(value,element,param){var length=this.getLength($.trim(value),element);return this.optional(element)||(length>=param[0]&&length<=param[1]);},min:function(value,element,param){return this.optional(element)||value>=param;},max:function(value,element,param){return this.optional(element)||value<=param;},range:function(value,element,param){return this.optional(element)||(value>=param[0]&&value<=param[1]);},email:function(value,element){return this.optional(element)||/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test(value);},url:function(value,element){return this.optional(element)||/^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value);},date:function(value,element){return this.optional(element)||!/Invalid|NaN/.test(new Date(value));},dateISO:function(value,element){return this.optional(element)||/^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(value);},dateDE:function(value,element){return this.optional(element)||/^\d\d?\.\d\d?\.\d\d\d?\d?$/.test(value);},number:function(value,element){return this.optional(element)||/^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(value);},numberDE:function(value,element){return this.optional(element)||/^-?(?:\d+|\d{1,3}(?:\.\d{3})+)(?:,\d+)?$/.test(value);},digits:function(value,element){return this.optional(element)||/^\d+$/.test(value);},creditcard:function(value,element){if(this.optional(element))return"dependency-mismatch";if(/[^0-9-]+/.test(value))return false;var nCheck=0,nDigit=0,bEven=false;value=value.replace(/\D/g,"");for(n=value.length-1;n>=0;n--){var cDigit=value.charAt(n);var nDigit=parseInt(cDigit,10);if(bEven){if((nDigit*=2)>9)nDigit-=9;}nCheck+=nDigit;bEven=!bEven;}return(nCheck%10)==0;},accept:function(value,element,param){param=typeof param=="string"?param.replace(/,/g,'|'):"png|jpe?g|gif";return this.optional(element)||value.match(new RegExp(".("+param+")$","i"));},equalTo:function(value,element,param){return value==$(param).val();}}});$.format=$.validator.format;})(jQuery);;(function($){var ajax=$.ajax;var pendingRequests={};$.ajax=function(settings){settings=$.extend(settings,$.extend({},$.ajaxSettings,settings));var port=settings.port;if(settings.mode=="abort"){if(pendingRequests[port]){pendingRequests[port].abort();}return(pendingRequests[port]=ajax.apply(this,arguments));}return ajax.apply(this,arguments);};})(jQuery);;(function($){$.each({focus:'focusin',blur:'focusout'},function(original,fix){$.event.special[fix]={setup:function(){if($.browser.msie)return false;this.addEventListener(original,$.event.special[fix].handler,true);},teardown:function(){if($.browser.msie)return false;this.removeEventListener(original,$.event.special[fix].handler,true);},handler:function(e){arguments[0]=$.event.fix(e);arguments[0].type=fix;return $.event.handle.apply(this,arguments);}};});$.extend($.fn,{delegate:function(type,delegate,handler){return this.bind(type,function(event){var target=$(event.target);if(target.is(delegate)){return handler.apply(target,arguments);}});},triggerEvent:function(type,target){return this.triggerHandler(type,[$.event.fix({type:type,target:target})]);}})})(jQuery);
/*
 * clearingInput: a jQuery plugin
 *
 * clearingInput is a simple jQuery plugin that provides example/label text
 * inside text inputs that automatically clears when the input is focused.
 * Common uses are for a hint/example, or as a label when space is limited.
 *
 * For usage and examples, visit:
 * http://github.com/alexrabarts/jquery-clearinginput
 *
 * Licensed under the MIT:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * Copyright (c) 2008 Stateless Systems (http://statelesssystems.com)
 *
 * @author   Alex Rabarts (alexrabarts -at- gmail -dawt- com)
 * @requires jQuery v1.2 or later
 * @version  0.1
 */

(function ($) {
  $.extend($.fn, {
    clearingInput: function (options) {
      var defaults = {blurClass: 'blur'};

      options = $.extend(defaults, options);

      return this.each(function () {
        var input = $(this).addClass(options.blurClass);
        var form  = input.parents('form:first');
        var label, text;

        text = options.text || textFromLabel() || input.val();

        if (text) {
          input.val(text);

          input.blur(function () {
            if (input.val() === '') {
              input.val(text).addClass(options.blurClass);
            }
          }).focus(function () {
            if (input.val() === text) {
              input.val('');
            }
            input.removeClass(options.blurClass);
          });

          form.submit(function() {
            if (input.hasClass(options.blurClass)) {
              input.val('');
            }
          });

          input.blur();
        }

        function textFromLabel() {
          label = form.find('label[for=' + input.attr('id') + ']');
          // Position label off screen and use it for the input text
          return label ? label.css({position: 'absolute', left: '-9999px'}).text() : '';
        }
      });
    }
  });
})(jQuery);
/**
 * jQuery.ScrollTo - Easy element scrolling using jQuery.
 * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
 * Dual licensed under MIT and GPL.
 * Date: 5/25/2009
 * @author Ariel Flesler
 * @version 1.4.2
 *
 * http://flesler.blogspot.com/2007/10/jqueryscrollto.html
 */
;(function(d){var k=d.scrollTo=function(a,i,e){d(window).scrollTo(a,i,e)};k.defaults={axis:'xy',duration:parseFloat(d.fn.jquery)>=1.3?0:1};k.window=function(a){return d(window)._scrollable()};d.fn._scrollable=function(){return this.map(function(){var a=this,i=!a.nodeName||d.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!i)return a;var e=(a.contentWindow||a).document||a.ownerDocument||a;return d.browser.safari||e.compatMode=='BackCompat'?e.body:e.documentElement})};d.fn.scrollTo=function(n,j,b){if(typeof j=='object'){b=j;j=0}if(typeof b=='function')b={onAfter:b};if(n=='max')n=9e9;b=d.extend({},k.defaults,b);j=j||b.speed||b.duration;b.queue=b.queue&&b.axis.length>1;if(b.queue)j/=2;b.offset=p(b.offset);b.over=p(b.over);return this._scrollable().each(function(){var q=this,r=d(q),f=n,s,g={},u=r.is('html,body');switch(typeof f){case'number':case'string':if(/^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(f)){f=p(f);break}f=d(f,this);case'object':if(f.is||f.style)s=(f=d(f)).offset()}d.each(b.axis.split(''),function(a,i){var e=i=='x'?'Left':'Top',h=e.toLowerCase(),c='scroll'+e,l=q[c],m=k.max(q,i);if(s){g[c]=s[h]+(u?0:l-r.offset()[h]);if(b.margin){g[c]-=parseInt(f.css('margin'+e))||0;g[c]-=parseInt(f.css('border'+e+'Width'))||0}g[c]+=b.offset[h]||0;if(b.over[h])g[c]+=f[i=='x'?'width':'height']()*b.over[h]}else{var o=f[h];g[c]=o.slice&&o.slice(-1)=='%'?parseFloat(o)/100*m:o}if(/^\d+$/.test(g[c]))g[c]=g[c]<=0?0:Math.min(g[c],m);if(!a&&b.queue){if(l!=g[c])t(b.onAfterFirst);delete g[c]}});t(b.onAfter);function t(a){r.animate(g,j,b.easing,a&&function(){a.call(this,n,b)})}}).end()};k.max=function(a,i){var e=i=='x'?'Width':'Height',h='scroll'+e;if(!d(a).is('html,body'))return a[h]-d(a)[e.toLowerCase()]();var c='client'+e,l=a.ownerDocument.documentElement,m=a.ownerDocument.body;return Math.max(l[h],m[h])-Math.min(l[c],m[c])};function p(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery);
/*
 *  PLANS
 */

// objx(plan).legs() - gets or sets the legs
objx.fn.legs = function(legs) {
	
	if (arguments.length === 0) {
		return objx(this.obj().legs);
	} else {
		this.obj().legs = legs;
		return this;
	}
	
};

// objx(plan).removeLeg( index ) - Removes a leg
objx.fn.removeLeg = function(index) {
	this.legs().removeAt(index);
};

// objx(plan).addLeg(leg) - Adds a leg
objx.fn.addLeg = function(leg) {
	this.legs().append(leg);
};

function hour(leg) {
	try {
		return leg.when.time.hour;
	} catch(e) {
		return 999999999;
	}
}

function minute(leg) {
	try {
		return leg.when.time.minute;
	} catch(e) {
		return 999999999;
	}
}

function sortLegTime(leg1, leg2) {
	var hourDiff = hour(leg1) - hour(leg2);
	var minDiff = minute(leg1) - minute(leg2);
	return (0 === hourDiff) ? minDiff : hourDiff;
}

//objx(plan).orderByTime() - Orders the plan by time
objx.fn.orderByTime = function() {
	var l = this.obj().legs;
	l.sort(sortLegTime);
};


/*
 *  LEGS
 */

// TODO: test this - https://iome.acunote.com/projects/9015/tasks/496
// objx(plan).createLegFromStar(star) - Creates and adds a leg from a star, returns objx(newleg)
objx.fn.createLegFromStar = function(star) {
	
	var type = 0; // default unknown

	if (IOItemType.experience === star.type) {
		if (star.details) {
			type = star.details.experienceType;
		}
	} else if (IOItemType.offer === star.type) {
		type = 6; // offer
	}
	
	var newLeg = {
		id: null,
		title: star.title || null,
		description: star.description || null,
		type: type,
		when: {},
		order: this.legs().obj().length || null,
		location: {
			lat: star.location.lat || null,
			lng: star.location.lng || null
		},
		experienceId: star.experienceId || null
	};

	this.addLeg(newLeg);

	return objx(newLeg);

};

// objx(leg).clearTime() - clears the time
objx.fn.clearTime = function() {

	this.obj().when.time = null;
	
};

objx.provides("objx.planDataPlugins");
/*
 *  IOOnce
 *  
 */

var IOOnceTimeouts = {};

var IOOnce = function( key, func, delay ){
	
	// default 500 delay
	delay = delay || 500;

	var timeout = IOOnceTimeouts[key];
	
	// clear the timeout
	if (timeout) {
		
		window.clearTimeout(timeout);
		IOOnceTimeouts[key] = null;
		
	}
	
	// set the next timeout
	IOOnceTimeouts[key] = window.setTimeout(func, delay);
	
};

objx.provides("IOOnce");
// http://dspwiki.iogloballtd.com/index.php/IOControl

// dependencies
objx.requires("objx.Class", "IOControl");

/*
 * IOControl
 * 
 * Represents the base class for UI controls
 * 
 * */
var IOControl = objx.Class({
	
	init: function(el) {
		
		// set the element
		this.element = (typeof el !== undefined) ? $(el) : $(window);
		
		// call created() if there is one
		if (this.created) {
			this.created.apply(this, arguments);
		}
	
	}
	
});

// provides...
objx.provides("IOControl");
// dependencies
objx.requires("objx.Class", "IOPage")
	.requires("IOControl", "IOPage");

/*
 * IOPage
 * 
 * Base class for pages
 * http://dspwiki.iogloballtd.com/index.php/Page
 * 
 * Requires: objx
 * 
 */

// define the page class
var IOPage = objx.Class(IOControl, {
	
	created: function() {
		// if there was an ajax update on the page, then reload the page to avoid displaying cached version.  
		if (this.clean()){
				
			// trigger the "pageCreated" function (if we have one)
			if (this.pageCreated) {
				this.pageCreated.apply(this, arguments);
			}
		
			// trigger the "ready" function (if we have one)
			if (this.pageReady) {
				$(objx.bind(this.pageReady, this));
			}

		}
	},
	
	clean: function() {
		if( this.getUpdateCookie() && this.getUpdateCookie() != "clean" ) {
			// clear page updated cookie as the page will be reloaded now with the fresh data.
			this.setUpdateCookie("clean");
			this.refreshPage();
			return false;
		}
		
		return true;
	},
	
	dataUpdated: function(dataName) {
		// record that some ajax updates have been done.
		this.setUpdateCookie(dataName);
	},
	
	getUpdateCookie: function() {
		return $.cookie('page-updated');
	},
	
	setUpdateCookie: function(newValue) {
		$.cookie('page-updated', newValue, { path: location.pathname });
	},
	
	
	refreshPage: function() {
		location.reload();
	},
	
	parseQuerystring: function(s) {

		var qs = {};
		s = s || window.location.search;

		s.replace(
			new RegExp( "([^?=&]+)(=([^&]*))?", "g" ),
			function( $0, $1, $2, $3 ){
				qs[ $1 ] = $3;
			}
		);

		return qs;

	}

});

objx.provides("IOPage");
// redirects the page
var IORedirect = function(url) {
  // switched window.location, more absolute than location.href
  // setTimeout fixes task 923.
	setTimeout(function() { window.location.href = url; }, 0);
};

IORedirect.toContacts = function() {
	IORedirect(IOPageRoot + "contacts");
};

IORedirect.toDetails = function(experienceId) {
	IORedirect( IORedirect.getDetailsLink(experienceId) );
};

IORedirect.toPlanEditor = function(planId) {
	IORedirect( IORedirect.getPlanEditorLink(planId) );
};

IORedirect.toPlanViewer = function(planId, code) {
	IORedirect( IORedirect.getPlanViewerLink(planId, code) );
};

IORedirect.getPlanViewerLink = function(planId, code) {
	if (code && "null" != code) {
		return IOPageRoot + "plans/" + planId + "/view?pkey=" + code;
	} else {
		return IOPageRoot + "plans/" + planId + "/view";
	}
};

IORedirect.getPlanEditorLink = function(planId) {
	return IOPageRoot + "plans/" + planId + "/edit";
};

IORedirect.getDetailsLink = function(experienceId) {
	return IOPageRoot + "experiences/" + experienceId;
};

IORedirect.getOffersAtLink = function(exp) {
	return IOPageRoot + "locations/" + exp.location.lat + "," + exp.location.lng + "/offers?r=100&at=" + exp.title;
};

IORedirect.getEventDetailsLink = function(exp) {
	return IOPageRoot + "locations/" + exp.location.lat + "," + exp.location.lng + "/experiences/search?at=" + exp.title;
};

IORedirect.searchExperiences = function(location, keywords) {
	return IOPageRoot + "locations/" + location.lat + "," + location.lng + "/experiences/search?q=" + keywords;
};

IORedirect.toHomepage = function(planId) {
	IORedirect(IOPageRoot);
};

IORedirect.toLogin = function() {
	IORedirect(IOPageRoot + "login");
};

IORedirect.logout = function(){
	IORedirect(IOPageRoot + "logout");
};

objx.provides("IORedirect");
objx.requires("objx.Class", "IOActivityService");

var IOActivityServiceClass = objx.Class({

	recordActivity: function(activityRecord) {

		var url = ('true' == IOEgg.session.loggedIn && IOEgg.session.user) ?

			'/users/' + IOEgg.session.user.id :

			'/sessions/' + $.cookie('dsp-sid');

		url += '/activities/' + new Date().getTime();

		$.ajax({
			type: "PUT",
			url: url,
			contentType: "application/json",
			data: $.toJSON(activityRecord, true)
		});

	}

});

// default instance
var IOActivityService = new IOActivityServiceClass();

objx.provides("IOActivityService");

objx.requires("objx.Class", "IOService");

/*
 *  Global service monitoring
 */
var IOServiceTracker = {
	
	pending: 0, // count of pending requests
	index: 0 // unique index for each service request
	
};

// add events to the IOServiceTracker
objx(IOServiceTracker).event("onWorking");	// ( status )
objx(IOServiceTracker).event("onIdle");		// ( status )
objx(IOServiceTracker).event("onFailure");	// ( status, error )

/*
 *  Represents a class that uses jQuery to access data services
 */
var IOjQueryDataService = objx.Class({

	// common events for all services
	onLoading: objx.event,
	onFinished: objx.event,
	onFailure: objx.event,
	
	errorStatusFromServer: "auto",
	
	// makes the ajax request
	makeRequest: function(options) {

		// raise the onLoading event
		this.onLoading(options);

		// setup defaults
		options.type = options.type || "GET";
		
		// increase the index
		var index = IOServiceTracker.index++;
		
		// wrap the success and failure methods
		options.csuccess = options.success;
		options.cerror = options.failure;
		options.success = objx.bind(this.service_success, this, options, index);
		options.error = objx.bind(this.service_failure, this, options, index);
		
		// indicate that the request has started
		this.service_requestStarted(options, index);
		
		// FIXME: REMOVE THIS HACK
		if( options.type.toLowerCase() != "get") {
			if (IOCurrentPage && IOCurrentPage.dataUpdated) {
				IOCurrentPage.dataUpdated("data-update");
			}
		}
		
		if (IOForceStandardHttpMethods) {
			
			if (options.type.toLowerCase() == "put" || options.type.toLowerCase() == "delete") {
				
				// add the _method workaround
				options.url += "?_method=" + options.type;
				
				// use POST
				options.type = "POST";
				
			}
			
		}
		
		// use jQuery to make the request
		$.ajax(options);
	
	},
	
	service_requestStarted: function(options, index) {
	
		IOServiceTracker.pending++;
		
		// raise the working event
		IOServiceTracker.onWorking(options.status);
		
	},
	service_requestFinished: function(options, index, success, error) {
		
		// decrease the pending counter
		IOServiceTracker.pending--;
		
		// are we now idle?
		if (IOServiceTracker.pending === 0) {
			
			// raise the idle event
			IOServiceTracker.onIdle( options.successStatus );
			
		}
		
		// was it a success?
		if (!success) {
		
			// if the error status is from server, display the error message received from the server
			errorStatus = options.errorStatus == this.errorStatusFromServer ? error.responseText : options.errorStatus;  
			// raise the failure event
			IOServiceTracker.onFailure(errorStatus, error);
			
			// raise the service failure event
			this.onFailure(options, error);
			
		}
		
		// raise the onFinished event
		this.onFinished(options, success, error);
		
	},
	
	service_success: function(options, index, response) {
	
		// finish the request
		this.service_requestFinished(options, index, true);
	
		// call the client success method (if there is one)
		if (options.csuccess) {
			options.csuccess(response);
		}
		
	},
	
	service_failure: function(options, index, response) {
		// RESTful services return 204 for successful delete, therefore forward it to service_success
		if (options.url && this.isDelete(options.url) && response.status == 204) {
			this.service_success(options, index, response);
		}
		else {
			// finish the request
			this.service_requestFinished(options, index, false, response);
		
			// call the client failure method (if there is one)
			if (options.cerror) {
				options.cerror(response);
			}
		}
		
	},
	
	isDelete: function(url) {
		var method = url.toLowerCase();
		if( method.length < 6 )
			{ return false; }
		return "delete" == method.substring(method.length - 6);
	}
	
});

// set the current data service
var IOService = IOjQueryDataService;

objx.provides("IOService");
objx.requires("objx.Class", "IODataManager");

var IODataManager = objx.Class({
	
	__data: null,
	
	init: function(){

		if (arguments.length > 0) {

			this.data(arguments[0]);

		} else {
			
			// save empty data
			this.__data = objx({});

		}
		
	},
	
	data: function(){
		
		if (arguments.length === 0) {
			
			return this.__data;
			
		} else {
			
			this.__data = objx(arguments[0]);

			return this;
		
		}
		
	}

});

objx.provides("IODataManager");
/*
 * Helper class for dealing with dates and times.
 * 
 */
var _twoDigit = function(value) {
	if(value === 0 || value) {
		var h = value.toString();
		if (h.length == 1) { h = "0" + h; }
		return h;
	}
	return null;
};

var IODateTime = {
		
	days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
	months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
	monthIndices: {"January":0, "February":1, "March":2, "April":3, "May":4, "June":5, "July":6, "August":7, "September":8, "October":9, "November":10, "December":11},
	shortMonths: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
	dateSuffixes: ["th","st","nd","rd","th","th","th","th","th","th",
	               "th","th","th","th","th","th","th","th","th","th",
	               "th","st","nd","rd","th","th","th","th","th","th",
	               "th","st"],
	
	/**
	 * Gets a Date object from milliseconds
	 */
	fromMilliseconds: function(m) {
		if( m === 0 || m ) { return new Date( m ); }
		return null;
	},
	
	/**
	 * Gets a Date expressed as milliseconds
	 */
	toMilliseconds: function(d) {
		if( d ) { return d.getTime(); }
		return null;
	},
	
	
	/**
	 * Converts a date into military time (i.e. 2000 for 8pm)
	 */
	toMilitaryTime: function(d) {
		if( d ) { return _twoDigit(d.getHours()) + _twoDigit(d.getMinutes()); }
		return null;
	},
	
	toNiceTime: function(d) {
		if( d ) { return _twoDigit(d.getHours()) + ":" + _twoDigit(d.getMinutes()); }
		return null;
	},
	
	toNiceDate: function(d) {
		if( d ) {
			return d.getDate() + "<sup>"+this.dateSuffixes[d.getDate()]+"</sup>" + " " + this.months[d.getMonth()] + " " + d.getFullYear();
		}
		return null;
	},
	
	fromNiceDate: function(niceDate) {
		if(niceDate) {
			var ioDate = this.fromNiceDateToIODate(niceDate);
			return new Date(ioDate.year, ioDate.month, ioDate.day);
		}
		return null;
	},

	fromNiceDateToIODate: function(niceDate) {
		if(niceDate) {
			var fields = niceDate.split(" ");
			if (3 == fields.length) {
				return {
					day: parseInt(fields[0].replace(/\D/,""), 10),
					month: this.toMonthIndex(fields[1]),
					year: parseInt(fields[2], 10)
				};
			}
		}
		return {};
	},
	
	toNiceDateTime: function(d) {
		if ( d ) {  
			return this.days[d.getDay()] + " " + d.getDate() + " " + this.shortMonths[d.getMonth()] + " " + this.toNiceTime(d); 
		}
		return null;
	},
	
	msToNiceTime: function(ms) {
		
		return this.toNiceTime(this.fromMilliseconds(ms));
		
	},
	
	msToNiceDateTime: function(ms) {
		
		return this.toNiceDateTime(this.fromMilliseconds(ms));
		
	},
	
	toMonthIndex: function(monthName) {
		return this.monthIndices[monthName];
	},
	
	/*
	 *  IOTimeStamp helpers
	 *  see http://apiwiki.iogloballtd.com/mediawiki/index.php/IOTimeStamp
	 */
	hasTime: function(timestamp) {
		return timestamp.time !== null;
	},
	setTime: function(timestamp, hours, minutes) {
		timestamp.time = {
			hour: hours,
			minute: minutes
		};
	},
	clearTime: function(timestamp) {
		timestamp.time = null;
	},
	hasDate: function(timestamp) {
		return timestamp.date !== null;
	},
	setDate: function(timestamp, day, month, year) {
		timestamp.date = {
			day: day,
			month: month,
			year: year
		};
	},
	clearDate: function(timestamp) {
		timestamp.date = null;
	}

};

objx.provides("IODateTime");
objx.requires("IOService", "IODataService");

var IODataService = objx.Class(IOService, {
	
	resource: "",
	
	onAllLoaded: objx.event,
	onLoaded: objx.event,
	onSaved: objx.event,
	onCreated: objx.event,
	onDeleted: objx.event,
	
	allStatus: "Loading items",
	findStatus: "Loading item",
	createStatus: "Creating item",
	saveStatus: "Saving item",
	delStatus: "Deleting item",
	
	allErrorStatus: "Unable to load items",
	findErrorStatus: "Unable to load item",
	createErrorStatus: "Unable to create item",
	saveErrorStatus: "Unable to save item",
	delErrorStatus: "Unable to delete item",
	
	allSuccessStatus: null,
	findSuccessStatus: null,
	createSuccessStatus: "New item was successfully created",
	saveSuccessStatus: "Changes were successfully saved",
	delSuccessStatus: "The item has been successfully deleted",
	
	/*
	 *  ALL
	 */
	all: function() {
		
		this.makeRequest({
			type: "GET",
			url: this.resource,
			dataType: "json",
			contentType: "application/json",
			success: objx.bind(this.all_success, this),
			
			status: this.allStatus,
			errorStatus: this.allErrorStatus,
			successStatus: this.allSuccessStatus
		});
		
	},
	all_success: function(r) {
		this.onAllLoaded(r.data);
	},

	/*
	 *  LOAD
	 */
	find: function( id ) {
		
		this.makeRequest({
			type: "GET",
			url: this.resource + "/" + id,
			dataType: "json",
			contentType: "application/json",
			success: objx.bind(this.find_success, this),
			
			status: this.findStatus,
			errorStatus: this.findErrorStatus,
			successStatus: this.findSuccessStatus
		});
		
	},
	find_success: function(r) {
		this.onLoaded(r.data);
	},


	/*
	 *  CREATE
	 */
	create: function( data ) {
		
		this.makeRequest({
			type: "POST",
			url: this.resource,
			dataType: "json",
			data: $.toJSON(data, true),
			contentType: "application/json",
			success: objx.bind(this.create_success, this),
			
			status: this.createStatus,
			errorStatus: this.createErrorStatus,
			successStatus: this.createSuccessStatus
		});
		
	},
	create_success: function(r) {
		this.onCreated(r.data);
	},


	/*
	 *  UPDATE
	 */
	save: function( id, data ) {
		
		this.makeRequest({
			type: "PUT",
			url: this.resource + "/" + id,
			contentType: "application/json",
			data: $.toJSON(data,true),
			dataType: "json",
			success: objx.bind(this.save_success, this),
			
			status: this.saveStatus,
			errorStatus: this.saveErrorStatus,
			successStatus: this.saveSuccessStatus
		});
		
	},
	save_success: function(r) {
		this.onSaved(r.data);
	},
	
	/*
	 *  DELETE
	 */
	del: function( id ) {
		
		this.makeRequest({
			type: "DELETE",
			url: this.resource + "/" + id,
			contentType: "application/json",
			dataType: "json",
			success: objx.bind(this.del_success, this, id),
			
			status: this.delStatus,
			errorStatus: this.delErrorStatus,
			successStatus: this.delSuccessStatus
		});
		
	},
	del_success: function(r) {
		this.onDeleted( typeof(r.data) !== "undefined" ? r.data : r );
	}
	
	
});

objx.provides("IODataService");
var IOModal = {
	
	bindEvents: function(){
		$(window).resize(objx.bind(this.window_resize, this));
		
		if (this.controlsOkEl){
			this.controlsOkEl.unbind("click").click(objx.bind(this.controlsOkEl_click, this));
		}
		if (this.controlsCancelEl){
			this.controlsCancelEl.unbind("click").click(objx.bind(this.controlsCancelEl_click, this));
		}
		
	},
	
	init: function(el, options){
		this.defaultOptions();
		this.el = el ? $(el) : this.el;
		for (var property in options){
			this[property] = options[property];
		}
		this.createPopup();
		this.popup();
		this.bindEvents();
	},
	
	defaultOptions: function(){
		this.el = $("<span/>").html("You must specify a body for your modal popup");
		this.overlayHeight = null;
		this.overlayWidth = null;
		this.overlayOpacity = 0.4;
		this.overlayBGColor = "#000";
		this.showOverlay = true;
        
		this.controls = null;
        
		this.width = "400px";
		this.height = "auto";
		this.overflow = "auto";
		this.top = "30px";
        
		this.onOk = null;
		this.okText = "Ok";
		this.onCancel = function(){
			this.close();
		};
		this.cancelText = "cancel";
	},
	
	createPopup: function(){
		var overlayDisplay = this.showOverlay ? "block" : "none";
		if ($(".IOModal-overlay").length === 0){
			this.overlayEl = $("<div/>")
				.addClass("IOModal-overlay")
				.css({
					width: this.overlayWidth ? this.overlayWidth : 
						($(document).width() > $(window).width()) ?
						$(document).width() :"100%",
					height: this.overlayHeight ? this.overlayHeight : 
						($(document).height() > $(window).height()) ?
						$(document).height() :"100%",
					opacity: this.overlayOpacity,
					"background-color": this.overlayBGColor,
					position: "absolute",
					top: 0,
					bottom: 0,
					"zIndex": "1000",
					display: overlayDisplay
				})
				.hide()
				.prependTo($("body"));
		} else {
			this.overlayEl = $(".IOModal-overlay");
		}
		
		$(".IOModal-container").remove();
		
		containerTop = $(document).scrollTop() + 30;
		
		this.containerEl = $("<div/>")
			.addClass("IOModal-container")
			.css({
				width: "100%",
				left: 0,
				position: "absolute",
				top: containerTop
			})
			.hide()
			.prependTo($("body"));
		
		$("IOModal-content").remove();
		
		this.contentEl = $("<div/>")
			.addClass("IOModal-content")
			.css({
				width: this.width,
				height: this.height,
				"background-color": this["background-color"],
				position: "relative",
				"zIndex": "1001",
				margin: "auto"
			})
			.hide()
			.appendTo(this.containerEl);
		
		if (this.controls && this.el.find(".IOModal-controls").length === 0) {
			
			switch (this.controls){
				case "OKCancel":
					this.controlsEl = $("<div/>").addClass("IOModal-controls").appendTo(this.el);
						this.controlsOkEl = $("<a/>").addClass("IOModal-ok").text(this.okText).appendTo(this.controlsEl);
						this.controlsEl.append($("<span/>").text("or"));
						this.controlsCancelEl = $("<a/>").addClass("IOModal-cancel").text(this.cancelText).appendTo(this.controlsEl);
					break;
				case "OK":
					this.controlsEl = $("<div/>").addClass("IOModal-controls").appendTo(this.el);
					this.controlsOkEl = $("<a/>").addClass("IOModal-ok").text(this.okText).appendTo(this.controlsEl);
					break;
			}
			
		}
		
		this.bindEvents();
		
	},
	
	popup: function(){
		this.contentEl.html(this.el);
		this.overlayEl.fadeIn("fast");
		this.containerEl.show();
		this.contentEl.show();
	},
	
	close: function(){
		this.contentEl.hide();
		this.containerEl.hide();
		this.overlayEl.fadeOut("fast");
	},
	
	window_resize: function(){
		if (!this.overlayWidth){
			if ($(document).width() > $(window).width()){
				this.overlayEl.css({
					width: $(document).width()
				});
			} else {
				this.overlayEl.css({
					width: "100%"
				});
			}
		}
		if (!this.overlayHeight){
			if ($(document).height() > $(window).height()){
				this.overlayEl.css({
					height: $(document).height()	
				});
			} else {
				this.overlayEl.css({
					height: "100%"
				});
			}
		}
	},
	
	controlsOkEl_click: function(){
		if (this.onOk){
			this.onOk();
		}
	},
	controlsCancelEl_click: function(){
		if (this.onCancel){
			this.onCancel();
		}
	},
	
	iFrame: function( url, width, height ) {
	
		var modalWidth = width || 650;
		var modalHeight = height || 550;
	
		this.element = $("<div>" +
								"<iframe src=\"" + url + "\" width=\"" + modalWidth + "px;\" height=\"" + (modalHeight - 40) + "px;\">" + 
								  "<p>Your browser does not support iframes.</p>" + 
								"</iframe>" +
							  "</div>");
		
		IOModal.init(this.element, {
			width: "" + modalWidth + "px",
			height: "" + modalHeight + "px",
			controls: "OKCancel",
			onOk: objx.bind(this.removeModal, this),
			onCancel: objx.bind(this.removeModal, this),
			okText: "ok"
		});
	},
	
	removeModal: function() {
		if (typeof(this.element) !== 'undefined') { this.element.remove(); }
		IOModal.close();
	}
};
var IOStringFilter = {
	
	url: function(s){
		
		var re1 = new RegExp('([a-zA-Z]*):\\/\\/[\\S]+(\\b|$)', "gim");
		var re2 = new RegExp('([^\\/])(www[\\S]+(\\b|$))', "gim");
		
		var a =  s.replace(re1,
                '<a href="$&" target="_blank">$&</a>');
		
		var b = a.replace(re2,
                '$1<a href="http://$2" target="_blank">$2</a>');
		
		return b.replace(/(^www[\S]+(\b|$))/gim,
                '<a href="http://$&" target="_blank">$&</a>');
		
	}
	
};


objx.provides("IOStringFilter");
// http://dspwiki.iogloballtd.com/index.php/IOPin

/*
 * IOPin
 * 
 * Helper Class for generating SRC urls for map pins
 * 
 * */
var IOPin = {

	key: [
	  { title : "Unknown", 
	    src : "/img/icons/pins/unknown-pin.png" },
	  { title : "Food", 
	    src : "/img/icons/pins/eat-pin.png" },
	  { title : "Drink", 
	    src : "/img/icons/pins/drink-pin.png" },
	  { title : "Shopping", 
	    src : "/img/icons/pins/shop-pin.png" }, 
	  { title : "Entertaining", 
	    src : "/img/icons/pins/see-pin.png" }, 
	  { title : "Events", 
	    src : "/img/icons/pins/do-pin.png" },
	  { title : "Vouchers", 
	    src : "/img/icons/pins/offer-pin.png" }, 
	  { title : "Promotions", 
	    src : "/img/icons/pins/offer-pin.png" }
	],

	shadow: {
	  dfl : "http://chart.apis.google.com/chart?chst=d_map_pin_shadow",
	  star : "http://chart.apis.google.com/chart?chst=d_map_xpin_shadow&chld=pin_star"
	},

	/**
	 * generates image + shadow urls from parameters
	 */
	getPin: function(experience, letter, starred) {

		var src = this.key[experience].src;

		if (starred) { 
			src = src.replace(/d_map_pin_letter/, "d_map_xpin_letter").replace("|000000", "|000000|FF0000");
		}

		if (typeof letter !== "undefined") {
			if (starred) {
				src = src.replace(/#/, "pin_star|"+String.fromCharCode(letter + 65));
			}
			else {
				src = src.replace(/#/, String.fromCharCode(letter + 65));
			}
		}
		else {
			src = src.replace(/#/, '');
		}

		// get shadow
		var shadow = starred ? this.shadow.star : this.shadow.dfl;

		// return name, pin and shadow
		return {
			title: this.key[experience].title, 
			img: src, 
			shadow: shadow
		};
		
	}
};

// provides...
objx.provides("IOPin");
objx.requires("objx.Class", "IOHub");

/*
 *  IOHub is an instance of a class that contains only
 *  events that are considered to be application wide.
 */
var IOHubClass = objx.Class({
	
	// Called when an experience has been clicked
	//
	//  sender				- The object raising the event
	//  id 					- The experience ID
	//  experience-details 	- (if available) The details of the experience
	//  options				- (optional) Any specific options
	//
	onExperienceSelected: objx.event, // ( sender, id, [ experience-details ], [ options ] )
	
	onOfferSelected: objx.event // ( sender, id, [ offer-details ], [ options ] )
	
});
//default instance
var IOHub = new IOHubClass();

objx.provides("IOHub");
// http://apiwiki.iogloballtd.com/mediawiki/index.php/IOExperienceService

objx.requires("objx.Class", "IOExperienceService")
	.requires("IOService", "IOExperienceService")
	.requires("IOActivityService", "IOExperienceService");
	
var IOExperienceService = objx.Class(IOService, {

	onExperienceSearchByKeyword: objx.event,
	onExperienceSearchByCategory: objx.event,
	onEventsAtSearch: objx.event,
	onExperienceDetails: objx.event,
	onExperienceEventDetails: objx.event,
	
	getExperienceDetails: function(exp){
		var id = exp.experienceId ? exp.experienceId : exp.refId;
		var url = IORedirect.getDetailsLink(id);
		
		this.makeRequest({
			url: url,
			beforeSend: function(xhrObj) {
				xhrObj.setRequestHeader("Accept","application/json");
			},
			dataType: "json",
			success: objx.bind(this.getExperienceDetails_success, this),
			status: "Looking for experience details"
		});
	},
	
	getExperienceDetailsById: function(id){
		var url = IORedirect.getDetailsLink(id);
		
		this.makeRequest({
			url: url,
			beforeSend: function(xhrObj) {
				xhrObj.setRequestHeader("Accept","text/html");
			},
			dataType: "text/html",
			success: objx.bind(this.getExperienceDetails_success, this),
			status: "Looking for experience details"
		});
	},
	
	getExperienceEvents: function(exp, html){
	
		var url = IORedirect.getEventDetailsLink(exp);
		
		this.makeRequest({
			url: url,
			beforeSend: function(xhrObj) {
				xhrObj.setRequestHeader("Accept","application/json");
			},
			dataType: "json",
			success: objx.bind(this.getExperienceEvents_success, this, html),
			status: "Looking for experience details"
		});
		
	},
	
	getExperienceEventDetailsById: function(id, context){
		var url = IORedirect.getDetailsLink(id);
		
		this.makeRequest({
			url: url,
			beforeSend: function(xhrObj) {
				xhrObj.setRequestHeader("Accept","application/json");
			},
			dataType: "json",
			success: objx.bind(this.getExperienceEventDetails_success, this, context),
			status: "Looking for event details"
		});
		
	},
	
	getExperienceDetails_success: function(response){
		this.onExperienceDetails(response);
	},
	
	getExperienceEvents_success: function(html, response){
		this.onExperienceDetails(html, response);
	},
	
	getExperienceEventDetails_success: function(context, response){
		this.onExperienceEventDetails(response, context);
	},
	
	
	experienceSearchByKeywordAndLocation: function( keywords, locationString, location ) {
	
		var activityRecord = {
			what: "searchByKeywordAndLocation",
  			which: keywords,
  			location: location
		};
	
		var status = "Looking for '" + keywords + "'";
		
		if (locationString && locationString !== "") {
			status += " near " + locationString;
		}
		
		status += "...";
	
		this.makeRequest({
			url: IORedirect.searchExperiences(location, keywords),
			dataType: "json",
			success: objx.bind(this.experienceSearchByKeyword_success, this, activityRecord),
			status: status
		});
		
	},
	
	experienceSearchByKeyword: function( location, radius, keywords ) {
	
		if (keywords) {

			var activityRecord = {
				what: "searchByKeyword",
	  			which: keywords,
	  			location: location
			};

			// make the request
			this.makeRequest({
				url: "/locations/" + location.lat + "," + location.lng + "/experiences/search?q=" + keywords + "&r=" + radius,
				dataType: "json",
				success: objx.bind(this.experienceSearchByKeyword_success, this, activityRecord),
				status: "Looking for \"" + keywords + "\""
			});

		} else {
			this.onExperienceSearchByKeyword([]);
		}
		$.cookie('search-keywords', (undefined === keywords) ? '' : keywords);
	},
	
	experienceSearchByKeyword_success: function(activityRecord, response) {
		activityRecord.whether = response.data.length;
		IOActivityService.recordActivity(activityRecord);
		this.onExperienceSearchByKeyword( response.data );
	},
	
	experienceSearchByCategory: function(location, radius, element){
	
		var cat = $(element);
		var cats = [];
		
		$(cat).each(function(){
			cats.push(this.query);
		});
		
		cats = cats.join(",");
		
		if (cats.length > 0){
		
			var activityRecord = {
				what: "searchByCategory",
	  			which: cats,
	  			location: location
			};
			
			this.makeRequest({
			
				url: "/locations/" + location.lat + "," + location.lng + "/experiences/by-category/" + cats + "?r=" + radius,
				dataType: "json",
				success: objx.bind(this.experienceSearchByCategory_success, this, activityRecord),
				status: "Searching categories"
				
			});
			
		} else {
			
			// return blank data
			this.onExperienceSearchByCategory([]);
			
		}
		
	},
	
	experienceSearchByCategory_success: function(activityRecord, response){
		
		activityRecord.whether = response.data ? response.data.length : 0;
		
		IOActivityService.recordActivity(activityRecord);
		this.onExperienceSearchByCategory(response.data);
		
	},
	
	eventsAtSearch: function( location, venueName ) {
	
		if (venueName) {
	
			var url = "/locations/" + location.lat + "," + location.lng + "/experiences/search?at=" + venueName;
			var status = "Looking for events at \"" + venueName + "\"";
	
			// make the request
			this.makeRequest({
				url: url,
				dataType: "json",
				success: objx.bind(this.eventsAtSearch_success, this),
				status: status
			});

		} else {
			this.onEventsAtSearch([]);
		}
		$.cookie('search-keywords', (null === venueName) ? '' : venueName);

	},
	
	eventsAtSearch_success: function( response ) {
		this.onEventsAtSearch( response.data );
	}
	
});

// default instance
var IOExperience = new IOExperienceService();

objx.provides("IOExperienceService");
objx.requires("IODataService", "IOStarService");

var IOStarService = objx.Class(IOService, {

	onSave: objx.event,

	/*
	 *  'save' method
	 *  PUT /stars
	 */
	save: function(stars) {

		// make the request
		this.makeRequest({
			url: IOEgg.session.restUrlPrefix + "/stars",
			type: "PUT",
			dataType: "json",
			contentType: "json",
			data: $.toJSON(stars,true),
			success: objx.bind(this.save_success, this),

			status: "Saving your starred items",
			errorStatus: "Unable to save your starred items"
		});

	},

	save_success: function( response ) {

		this.onSave( response.data );

	}

});

// default instance
var IOStars = new IOStarService();

objx.provides("IOStarService");
objx.requires("objx.Class", "IOPlanService")
	.requires("IODataService", "IOPlanService");

var IOPlanService = objx.Class(IODataService, {
	
	allStatus: "Loading plans",
	findStatus: "Loading plan",
	createStatus: "Creating a new plan",
	saveStatus: "Saving plan changes",
	delStatus: "Deleting plan",
	
	allErrorStatus: "Failed to load plans",
	findErrorStatus: "Failed to load plan details",
	createErrorStatus: "Cannot create plan",
	saveErrorStatus: "Your changes have not been saved",
	delErrorStatus: "That plan could not be deleted",
	
	allSuccessStatus: null,
	findSuccessStatus: null,
	createSuccessStatus: null,
	saveSuccessStatus: null,
	delSuccessStatus: "The plan was successfully deleted",
	
	init: function() {
		this.resource = IOEgg.session.restUrlPrefix + "/plans";
	},

	/*
	 *  'findComments' method
	 *  GET /plans/{id}/comments
	 */
	onCommentsLoaded: objx.event,
	onAutoPlanLoaded: objx.event,

	findComments: function(id) {

		// make the request
		this.makeRequest({
			url: "/plans/" + id + "/comments",
			type: "GET",
			dataType: "json",
			success: objx.bind(this.findComments_success, this),

			status: "Loading plan comments",
			errorStatus: "Unable to load plan comments"
		});

	},

	findComments_success: function( response ) {

		this.onCommentsLoaded( response.data );

	},
	
	generateAutoPlan: function(location, cats, count, index) {
		
		count = count || 4;
		
		this.makeRequest({
			url: "/locations/"+location.lat+","+location.lng+"/recommendations/experiences/by-category/"+cats+"?r=5000&n="+count,
			type: "GET",
			dataType: "json",
			success: objx.bind(this.autoPlan_success, this, index),

			status: "Hang on while I think up some suggestions",
			errorStatus: "Unable to find suggestions for your plan"
		});
		
	},
	
	autoPlan_success: function(index, response){
		
		this.onAutoPlanLoaded(response.data, index);
		
	}
	
});

// create a default instance
var IOPlan = new IOPlanService();

// keep track of whether all plans have loaded or not
IOPlan.hasAllLoaded = false;
IOPlan.onAllLoaded(function(){
	IOPlan.hasAllLoaded = true;
});

objx.provides("IOPlanService");
objx.requires("objx.Class", "IOFullPostcodeGeocoderService");

// requires Google Maps API

var IOFullPostcodeGeocoderService = objx.Class({
	
	ACCURACY_CERTAIN_LEVEL: 8,
	
	showMessages: false,
	
	failureStatus: "Unable to get geocoding information at this time",
	
	onOptions: objx.event, // ( data )
	onNoOptions: objx.event, // ( data )
	onCertainOption: objx.event, // ( placemark, data )
	onFailure: objx.event, // ( code, data )
	
	init: function() {
		localSearch = new google.search.LocalSearch();
		localSearch.setCenterPoint("London, UK");
		localSearch.setSearchCompleteCallback(null, objx.bind(this.find_response, this));

		if (!this.showMessages) {
			this.failureStatus = null;
		}
		
	},
	
	find: function( s ) {
		this.lastSuppliedSearchTerms = s;
		s = s + ", uk";
		this.notAlreadySearchedAgain = true;
		this.doFind(s);
	},
	
	doFind: function( s ) {
		if (this.showMessages) {
			//console.log('geocode: ' + s);
			IOServiceTracker.onWorking("Looking up Geocoding information for \"" + s + "\"");
		} else {
			IOServiceTracker.onWorking();
		}
		localSearch.execute(s);
		
	},
	
	find_response: function() {
		IOServiceTracker.onIdle();

		if (localSearch.results[0]) {
			var resultLat = localSearch.results[0].lat;
			var resultLng = localSearch.results[0].lng;
			if (this.showMessages) {
				//console.log('local search result: ' + resultLat + ', ' + resultLng);
			}
			this.onCertainOption({'lat': resultLat, 'lng': resultLng});
		}
		else if (this.notAlreadySearchedAgain) {
			this.notAlreadySearchedAgain = false;
			this.doFind(this.lastSuppliedSearchTerms);
		}
		else {
			this.onNoOptions();
		}					
	}

});

objx.provides("IOFullPostcodeGeocoderService");
objx.requires("objx.Class", "IOGeocoderService");

// requires Google Maps API

var IOGoogleGeocoderService = objx.Class({
	
	ACCURACY_CERTAIN_LEVEL: 8,
	
	showMessages: false,
	
	failureStatus: "Unable to get geocoding information at this time",
	
	onOptions: objx.event, // ( data )
	onNoOptions: objx.event, // ( data )
	onCertainOption: objx.event, // ( placemark, data )
	onFailure: objx.event, // ( code, data )
	
	init: function() {
		this.geocoder = new GClientGeocoder();
		
		if (!this.showMessages) {
			this.failureStatus = null;
		}
		
	},
	
	find: function( s ) {
		
		if (this.showMessages) {
			IOServiceTracker.onWorking("Looking up Geocoding information for \"" + s + "\"");
		} else {
			IOServiceTracker.onWorking();
		}
		
		// trigger the search
		this.geocoder.getLocations(s, objx.bind(this.find_response, this));
		
	},
	
	find_response: function( data ) {
		
		IOServiceTracker.onIdle();
		
		if (data.Status.code == 200) {
			
			if (data.Placemark.length === 0) {
				
				// nothing
				this.onNoOptions( data );
				
			} else if (data.Placemark.length === 1 && data.Placemark[0].Accuracy >= this.ACCURACY_CERTAIN_LEVEL) {
				
				// certain
				
				this.onCertainOption( data.Placemark[0], data );
				
			} else {
				
				// options
				
				this.onOptions( data );
				
			}
			
		} else {
		
			// failure
			IOServiceTracker.onFailure( this.failureStatus );
		
			// raise the failure event
			this.onFailure(data.Status.code, data);
				
		}
		
	}
	
});

var IOGeocoderService = IOGoogleGeocoderService;
var IOGeocoder = new IOGeocoderService();

objx.provides("IOGeocoderService");
// http://apiwiki.iogloballtd.com/mediawiki/index.php/IOOfferService

objx.requires("objx.Class", "IOOfferService")
	.requires("IOService", "IOOfferService")
	.requires("IOActivityService", "IOOfferService");
	
var IOOfferService = objx.Class(IOService, {

	onOfferSearch: objx.event,
	onOffersAtSearch: objx.event,
	onOfferSearchHTML: objx.event,
	
	offersAt: function(exp){
		var url = IORedirect.getOffersAtLink(exp);
		
		this.makeRequest({
			url: url,
			beforeSend: function(xhrObj) {
				xhrObj.setRequestHeader("Accept","application/json");
			},
			dataType: "json",
			success: objx.bind(this.offersAt_success, this)
		});
	},

	offersAt_success: function(response) {
		this.onOffersAtSearch( response.data );
	},
	
	offerSearch: function( location, radius ) {

		if (location){
		
			var activityRecord = {
				what: "search",
	  			which: "offers",
	  			location: location
			};

			// make the request
			this.makeRequest({
				url: "/locations/" + location.lat + "," + location.lng + "/offers?r=" + radius,
				beforeSend: function(xhrObj) {
					xhrObj.setRequestHeader("Accept","application/json");
				},
				dataType: "json",
				success: objx.bind(this.offerSearch_success, this, activityRecord)//,
				//status: "Looking for offers"
			});
			
		} else {
			
			// return blank data
			this.onOfferSearch([]);
			
		}
			
	},
	
	offerSearch_success: function(activityRecord, response) {
		activityRecord.whether = response.data.length;
		IOActivityService.recordActivity(activityRecord);
		this.onOfferSearch( response.data );
	},
	
	offerSearchHTML: function( location ) {

		// make the request
		this.makeRequest({
			url: "/locations/" + location.lat + "," + location.lng + "/offers",
			beforeSend: function(xhrObj) {
				xhrObj.setRequestHeader("Accept","text/html");
			},
			dataType: "text/html",
			success: objx.bind(this.offerSearchHTML_success, this)//,
			//status: "Looking for offers"
		});
			
	},
	
	offerSearchHTML_success: function( html ) {
		this.onOfferSearchHTML( html );
	}
	
});

// default instance
var IOOffer = new IOOfferService();

objx.provides("IOOfferService");
objx.requires("objx.Class", "IOEmailService")
	.requires("IOService", "IOEmailService");

IOEmailService = objx.Class(IOService, {
	
	onLoading: objx.event,

	sendingStatus: "Sending Email...",
	successStatus: "Email sent successfully.",
	
	send: function(message) {

		this.onLoading();
		
		this.makeRequest({
			type: "POST",
			url: "/emails/send",
			data: message,
			dataType: "text",

			status: this.sendingStatus,
			errorStatus: this.errorStatusFromServer,
			successStatus: this.successStatus
		});
		
	}
	
});

objx.provides("IOEmailService");
objx.requires("objx.Class", "IOSMSService")
	.requires("IOService", "IOSMSService");

IOSMSService = objx.Class(IOService, {
	
	onLoading: objx.event,

	sendingStatus: "Sending SMS...",
	successStatus: "SMS Sent successfully.",
	
	send: function(message) {

		this.onLoading();
		
		this.makeRequest({
			type: "POST",
			url: "/sms/send",
			data: message,
			dataType: "text",
			
			status: this.sendingStatus,
			errorStatus: this.errorStatusFromServer,
			successStatus: this.successStatus
		});
		
	}
	
});

objx.provides("IOSMSService");
objx.requires("IOService", "IORecommendationService");

var IORecommendationService = objx.Class(IOService, {
	
	find: function(location, count, category, search, success, error) {
		
		var params = {
			n: count || 1
		};
		
		this.makeRequest({
			
			url: "/locations/" + location.lat + "," + location.lng + "/recommendations/places/by-category/" + category,
			type: "GET",
			dataType: "json",
			data: params,
			success: objx.bind(this.find_success, this, success),
			error: objx.bind(this.find_error, this, error)
			
		});
		
	},
	
	findOne: function(location, category, search, success, error) {
		this.find(location, 1, category, search, success, error);
	},
	
	findOneByCategory: function(location, category, success, error) {
		this.findOne(location, category, null, success, error);
	},
	
	find_success: function(success, index, response){
		success(response);
	},
	
	find_error: function(error, index, response){
		error(response);
	}
	
});

objx.provides("IORecommendationService");
objx.requires("objx.Class", "IOFacebookConnectService")
	.requires("IOService", "IOFacebookConnectService");

var IOFacebookConnect = objx.Class(IOService, {
	
	onLoading: objx.event,
	onConnectSuccess: objx.event,

	connect: function(connectData) {

		this.onLoading();
		
		this.makeRequest({
			type: "POST",
			url: "/fbconnect",
			data: connectData,
			success: objx.bind(this.connect_success, this),

			errorStatus: this.errorStatusFromServer
		});
		
	},
	
	connect_success: function() {
		this.onConnectSuccess();
	}
	
});

// create a default instance
var IOFacebookConnectService = new IOFacebookConnect();

objx.provides("IOFacebookConnectService");
objx.requires("IOService", "IOHappeningService");

var IOHappeningService = objx.Class(IOService, {
	
	onStoriesLoaded: objx.event,
	
	whenever: function(count) {
		
		var params = {
			n: count || 1
		};
		
		this.makeRequest({
			
			url: "/happening/whenever",
			type: "GET",
			dataType: "json",
			data: params,
			success: objx.bind(this.whenever_success, this),
			error: objx.bind(this.whenever_error, this)
			
		});
		
	},
	
	whenever_success: function(response) {
		this.onStoriesLoaded(response.data);
	},
	
	whenever_error: function() {
		// TODO: handle errors!
	}
	
});

objx.provides("IOHappeningService");
objx.requires("objx.Class", "IOPlanDataManager")
	.requires("IODataManager", "IOPlanDataManager")
	.requires("objx.each", "IOPlanDataManager");

// TODO: use src/objx/plan-data-plugins.js
// https://iome.acunote.com/projects/9015/tasks/495

var IOPlanDataManager = objx.Class(IODataManager, {

	getPlanId: function(title){
		return this.data().obj().id;
	},

	getTitle: function(){
		return this.data().obj().title;
	},
	
	setTitle: function(title){
		this.data().obj().title = title;
	},
	
	setStart: function(start){
		this.data().obj().start = start;
	},
	
	setPrivateKey: function(privateKey){
		this.data().obj().privateKey = privateKey || null;
	},
	
	isPrivate: function(){
		var key = this.getPrivateKey();
		if (key) {
			return "null" != key;
		}
		return false;
	},
	
	getPrivateKey: function(){
		return this.data().obj().privateKey;
	},
	
	legs: function(){
		return objx(this.data().obj().legs);
	},
	
	removeLegByIndex: function(index){
		
		this.legs().removeAt(index);
		
		this.orderLegs();
				
	},
	
	getLength: function(){
		return this.data().obj().legs ? this.data().obj().legs.length : 0;
	},
	
	orderLegs: function(){
		
		if (arguments.length > 0){
			
			this.data().obj().legs = arguments[0];
			
		}
		
		this.legs().each(function(leg,i){
			
			leg.order = i;
			
		});
		
	},
	
	addLeg: function(leg){
	
		leg.order = this.getLength();
		
		objx(this.data().obj().legs).append(leg);
		
	},
	
	changeLeg: function(leg, index){
		
		this.data().obj().legs[index] = leg;
		
	},
	
	createLeg: function(star){
				
		var type = 0;
		
		if (star.type == IOItemType.experience) {
			if (star.details) {
				type = star.details.experienceType;
			} else {
				type = 0;
			}
		} else {
			type = star.type;
		}
		
		var newLeg = {
			id: null,
			title: star.title || null,
			description: star.description || null,
			type: type,
			when: {},
			order: this.legs().obj().length || 0,
			location: {
				lat: star.location.lat || null,
				lng: star.location.lng || null
			},
			experienceId: star.refId || null,
			experienceTitle: star.title || null
		};
		
		this.addLeg(newLeg);
		
		return newLeg;
		
	},
	
	createLegFromItem: function(item){
		// FIXME some restructuring of voucher and experience data might be needed to be able to use the same function
		if (item.voucherId)
			{return this.createLegFromOffer(item);}
		else if (item.experienceId)
			{return this.createLegFromExp(item);}
		else
			{return null;}
	},
	
	createLegFromExp: function(experience){
		
		var newLeg = {
			id: null,
			title: experience.title || null,
			description: experience.shortDescription || null,
			type: experience.type || 0,
			when: {},
			order: this.legs().obj().length || null,
			location: experience.location ? {
				lat: experience.location.lat || null,
				lng: experience.location.lng || null
			} : null,
			experienceId: experience.experienceId || null,
			experienceTitle: experience.title || null
		};
		
		this.addLeg(newLeg);
		
		return newLeg;
		
	},
	
	createLegFromOffer: function(offer){
		
		var newLeg = {
			id: null,
			title: offer.title || null,
			description: offer.name || null,
			type: 6,
			when: {},
			order: this.legs().obj().length || null,
			location: offer.location ? {
				lat: offer.location.lat || null,
				lng: offer.location.lng || null
			} : null,
			experienceId: offer.experienceId || null,
			experienceTitle: offer.title || null
		};
		
		this.addLeg(newLeg);
		
		return newLeg;
		
	},
	
	orderLegsByTime: function(){
		this.data().orderByTime();
		this.orderLegs();
	}

});

objx.provides("IOPlanDataManager");
objx.requires("objx.Class", "IOStarDataManager")
	.requires("objx.find", "IOStarDataManager")
	.requires("IOStarService", "IOStarDataManager")
	.requires("IOOnce", "IOStarDataManager");

var IOStarDataManager = objx.Class(IODataManager, {
		
	service: null,
		
	init: function(service, data) {

		this.service = service;
		this.data = objx(data);
		
	},
	
	isStarred: function(type, refId) {
		
		return this.data.find(function(item){
			
			return item.refId == refId && item.type == type;
			
		}).is("something");

	},

	star: function(type, data) {

		var newStarredItem;
		
		switch (type) {
			case IOItemType.experience:
				newStarredItem = this.createFromExperience(data);
				break;
			case IOItemType.offer:
				newStarredItem = this.createFromOffer(data);
				break;
			default:
				throw "Cannot star an item of type " + type + ".";
		}
		
		this.data.append(newStarredItem);
		this.save();

		return newStarredItem;
	},

	unstar: function(type, refId) {

		this.data.remove(this.data.find(function(item){
			return item.refId == refId && item.type == type;
		}).obj());
		
		this.save();

	},
	
	save: function() {
	
		IOOnce("save-starred-items", objx.bind(function(){
			
			this.service.save(this.data.obj());
			
		}, this));
		
	},
	
	createFromExperience: function( experience ) {
		
		return {
			type: IOItemType.experience,
			refId: experience.experienceId,
			title: experience.title || null,
			description: experience.shortDescription || null,
			location: experience.location || null,
			details: {
				experienceType: experience.type || 0
			}
		};
		
	},
	
	createFromOffer: function( offer ) {
		return {
			type: IOItemType.offer,
			refId: offer.voucherId,
			title: offer.title || null,
			description: offer.name || null,
			location: offer.location || null,
			details: offer
		};
		
	}

});

var IOStarData = new IOStarDataManager(IOStars, IOEgg.stars);

objx.provides("IOStarDataManager");
objx.requires("objx.Class", "IOHappeningManager")
	.requires("IOHappeningService", "IOHappeningManager");

var IOHappeningManager = objx.Class({
	
	onItem: objx.event,
	
	offset: 100,
	position: 0,
	buffer: [],
	
	init: function() {
		
		// create a new buffer
		this.buffer = [];
		
		// create happening service
		this.happeningService = new IOHappeningService();
		this.happeningService.onStoriesLoaded(objx.bind(this.happeningService_onStoriesLoaded, this));
		
	},
	
	getItem: function() {
		
		var p = this.position;
		
		if (p + 1 > this.buffer.length) {
			
			if (0 === this.buffer.length) {

				// we need to load more items
				this.loadNextSetOfItems();

			} else {

				// Reuse existing items
				this.position = 0;
				this.getNextItem();

			}
			
		} else {
			
			// return the next item
			this.getNextItem();
			
		}
		
	},
	
	getNextItem: function() {
		
		var item = this.buffer[this.position];

		// raise the event
		this.onItem(item);
		
		// increase the position
		this.position++;
	
	},
	
	loadNextSetOfItems: function() {
		
		// load more stories...
		this.happeningService.whenever(this.offset);
		
	},
	
	happeningService_onStoriesLoaded: function(stories) {
		
		// put the stories in the buffer
		objx(stories).each(objx.bind(function(story){
			this.buffer.push(story);
		}, this));
		
		// and return the next one
		this.getNextItem();
		
	}
	
});

objx.provides("IOHappeningManager");
objx.requires("IORedirect", "IOPlanHelper");
objx.requires("IOPlanService", "IOPlanHelper");

var IOPlanHelper = {
	
	// creates a new plan and redirects to the editor
	createAndEdit: function() {
		
		IOPlan.onCreated(objx.bind(this.createAndEdit_onCreated, this));
		IOPlan.create();
		
	},
	
	createAndEdit_onCreated: function( plan ) {
		
		// redirect to the plan editor
		IORedirect.toPlanEditor(plan.id);
		
	},
	
	getPlanTitle: function(plan){
		
		return plan.title || "Untitled";
		
	},
	
	getLegTitle: function(leg){
		
		return leg.title || "Untitled";
		
	}
	
};

objx.provides("IOPlanHelper");
objx.requires("objx.Class", "IOSharingInfo");

var IOSharingInfo = objx.Class({
	
	sms: false,
	label: "Item",
	
	init: function(item) {
		this.dataObject = item;
	},
	
	getWho: function() {
		return IOEgg.session.user ? IOEgg.session.user.displayName : "Somebody";
	},
	
	getFromAddress: function() {
		return IOEgg.session.user ? IOEgg.session.user.email : "plan@plotstar.com";
	},
	
	getEmailMessage: function() {
		throw "You must override the getEmailMessage method in classes deriving IOMapInfoHandler.";
	},
	
	getEmailTemplate: function() {
		throw "You must override the getEmailTemplate method in classes deriving IOMapInfoHandler.";
	},
	
	getSMSMessage: function(){
		throw "You must override the getSMSMessage method in classes deriving IOMapInfoHandler.";
	},

	getUrl: function(){
		throw "You must override the getUrl method in classes deriving IOMapInfoHandler.";
	},
	
	getTitle: function(){
		return this.dataObject.title;
	}

});

objx.provides("IOSharingInfo");
objx.requires("objx.Class", "IOPlanSharingInfo")
    .requires("IOSharingInfo", "IOPlanSharingInfo");

var IOPlanSharingInfo = objx.Class( IOSharingInfo, {

	sms: true,
	label: "Plan",
	
	getEmailMessage: function( toAddress ) {
		var who = this.getWho();
		return {
			email_from : this.getFromAddress(),
			email_to: toAddress,
			email_subject : who + " has sent you a Plotstar plan",
			email_message : "Hi, \n\n" +
			  who + " has sent you Plotstar plan '"+ this.dataObject.title + "'.  To see the plan, follow this link: " + this.getPlanUrl() + "\n\n" +
				"To learn more about Plotstar go to http://www.plotstar.com/\n\n" +
				"Thanks\n" +
				"Plotstar Team"
		};
	},

	getEmailTemplate: function() {
		return "plan";
	},

	getSMSMessage: function( toAddress ){
		return {
			sms_to: toAddress,
			sms_message : this.getWho() + " has sent you a Plotstar plan: " + this.getPlanUrl() 
		};
	},

	getPlanUrl: function(){
		var url = ('/' == window.location.pathname) ? window.location.href : window.location.href.split(window.location.pathname,1);
		var planUrl = url + IORedirect.getPlanViewerLink(this.dataObject.id, this.dataObject.privateKey);
		//FIXME - get rid of the hack below
		return planUrl.replace('//plans', '/plans');
	}, 
	
	getUrl: function(){
		return this.getPlanUrl();
	}
	
	
});

objx.provides("IOPlanSharingInfo");
objx.requires("objx.Class", "IOExperienceSharingInfo")
    .requires("IOSharingInfo", "IOExperienceSharingInfo");

var IOExperienceSharingInfo = objx.Class( IOSharingInfo, {
	
	label: "Experience",
	
	getEmailMessage: function( toAddress ) {
		var who = this.getWho();
		return {
			email_from : this.getFromAddress(),
			email_to: toAddress,
			email_subject : who + " has sent you a Plotstar experience",
			email_message : "Hi, \n\n" +
			  who + " has sent you Plotstar experience '"+ this.dataObject.title + "'.  To see the experience, follow this link: " + this.getExperienceUrl() + "\n\n" +
				"To learn more about Plotstar go to http://www.plotstar.com/\n\n" +
				"Thanks\n" +
				"Plotstar Team"
		};
	},

	getEmailTemplate: function() {
		return "experience";
	},

	getSMSMessage: function( toAddress ){
		return {
			sms_to: toAddress,
			sms_message : this.getWho() + " has sent you a Plotstar experience: " + this.getExperienceUrl() 
		};
	},

	getExperienceUrl: function(){
		var url = ('/' == window.location.pathname) ? window.location.href : window.location.href.split(window.location.pathname,1);
		var experienceUrl = url + IORedirect.getDetailsLink(this.dataObject.experienceId);
		
		//FIXME - get rid of the hack below
		return experienceUrl.replace('//experiences', '/experiences');
	}, 
	
	getUrl: function(){
		return this.getExperienceUrl();
	}
	
	
});

objx.provides("IOExperienceSharingInfo");
objx.requires("objx.Class", "IOOfferSharingInfo")
    .requires("IOSharingInfo", "IOOfferSharingInfo");

var IOOfferSharingInfo = objx.Class( IOSharingInfo, {

	label: "Offer",
	
	getEmailMessage: function( toAddress ) {
		var who = this.getWho();
		return {
			email_from : this.getFromAddress(),
			email_to: toAddress,
			email_subject : who + " has sent you an offer from Plotstar",
			email_message : "Hi, \n\n" +
			  who + " has sent you the offer '"+ this.dataObject.name + " at "+ this.dataObject.title + "'." +
				"To learn more about Plotstar go to http://www.plotstar.com/\n\n" +
				"Thanks\n" +
				"Plotstar Team"
		};
	},

	getEmailTemplate: function() {
		return "offer";
	},

	getSMSMessage: function( toAddress ){
		return {
			sms_to: toAddress,
			sms_message : this.getWho() + " has sent you a Plotstar offer: " + this.dataObject.name + " at "+ this.dataObject.title + "'."
		};
	}, 
	
	getExperienceUrl: function(){
		var url = ('/' == window.location.pathname) ? window.location.href : window.location.href.split(window.location.pathname,1);
		var experienceUrl = url + IORedirect.getDetailsLink(this.dataObject.experienceId);
		
		//FIXME - get rid of the hack below
		return experienceUrl.replace('//experiences', '/experiences');
	}, 
	
	getUrl: function(){
		return this.getExperienceUrl();
	},
	
	getTitle: function(){
		return this.dataObject.name + " at "+ this.dataObject.title;
	}
	
});

objx.provides("IOOfferSharingInfo");
var IOOfferViewer = {

	modalIFrame: function(url, offerProvider, offerTitle) {
		if (url && 0 < url.length) {

			IOModal.iFrame(url);

			var activityRecord = {
				what: "offerView",
	  			which: offerProvider + "~" + offerTitle,
	  			whether: url,
	  			location: IOEgg.location
			};

			IOActivityService.recordActivity(activityRecord);
		}
	}

};
objx.requires("IOControl", "IOStatusBox")
	.requires("IOService", "IOStatusBox");


var IOStatusBusyImage = "/img/loaders/status-busy.gif";	

var IOStatusBox = objx.Class(IOControl, {

	ERROR_CSS_CLASS: "error-status",
	SHOW_DELAY: 500,
	HIDE_DELAY: 250,
	AUTOFADE_DELAY: 1000,

	created: function() {
		
		// create the element
	
		this.statusEl = $("<span />");
		
		this.busyImgEl = $("<img src=\"" + IOStatusBusyImage + "\" alt=\"Please wait\" class=\"busy-image\" />");
		
		this.hideEl = $("<a>Hide</a>")
						.nolink()
						.addClass("hide")
						.click(objx.bind(function(){ this.clear(); }, this));
		
		this.element = $("<div class=\"status\" />")
						.append(this.busyImgEl, this.statusEl, this.hideEl);
								
		this.container = $("<div class=\"status-box\" />")
						.append(this.element);
		
		// and add it to the body
		$("body").append(this.container);

		// bind to the IOServiceTracker events
		IOServiceTracker
			.onWorking(objx.bind(this.service_onWorking, this))
			.onIdle(objx.bind(this.service_onIdle, this))
			.onFailure(objx.bind(this.service_onFailure, this));
		
	},
	
	// set the status
	status: function(s, isError, autofade) {

		this._clearTimeout();

		this.timeout = window.setTimeout(objx.bind(this._setStatus, this, s, isError, autofade), this.SHOW_DELAY);
		
	},
	
	_clearTimeout: function() {
		
		if (this.timeout) {
			
			window.clearTimeout(this.timeout);
			this.timeout = null;
			
		}
		
	},
	
	_setStatus: function(s, isError, autofade) {
	
		this._clearTimeout();
	
		if (s) {
		
			// set the error class if this is an error
			if (isError) {
				
				this.element.addClass(this.ERROR_CSS_CLASS);
				s += " - Please try again";
				this.busyImgEl.hide();
				this.hideEl.show();
				
			} else {
				
				this.element.removeClass(this.ERROR_CSS_CLASS);
				
				if (!autofade) {
					this.busyImgEl.show();
				}
				
				this.hideEl.hide();
				
			}
		
			// set the status
			this.statusEl.text(s);
			this.container.show();
		
			if (autofade) {
				
				this.busyImgEl.hide();
				
				// fade this out in a bit
				this.timeout = window.setTimeout(objx.bind(function(){
					this.clear();
				}, this), this.AUTOFADE_DELAY);
				
			}
		
		}
		
	},
	
	// clears the status
	clear: function() {
		
		this._clearTimeout();
		
		// hide the status
		this.timeout = window.setTimeout(objx.bind(function(){
			
			this.container.fadeOut("slow");
			
		}, this), this.HIDE_DELAY);
		
	},
	
	
	service_onWorking: function(status) {
		this.status(status, false, false);
	},
	service_onIdle: function(status) {
		
		if (status) {
		
			this.status(status, false, true);
		
		} else {
		
			this.clear();
		
		}
		
	},
	service_onFailure: function(status) {
		
		this.status(status, true, false);
		
	}

});

objx.provides("IOStatusBox");
objx.requires("objx.Class", "IODroppable");

var IODroppable = objx.Class({
	
	onItemDropped: objx.event,
	
	init: function(el, options) {
		// set the element
		this.element = $(el);
		
		this.makeItDroppable(options);
	},
	
	makeItDroppable: function(options) {

		var accept = '.list-marker, .dragablecopy, ';
		accept += options ? options.accept : null;
		
		this.element.droppable({
			accept: accept,
			drop: objx.bind(function(event, ui) {
				this.backToNormal();
				
				if(this.onItemDropped) {
					this.onItemDropped(ui.draggable.data("data"), this.element);
				}
				
			}, this),
		
			over: objx.bind(this.dragAcceptable, this),
			out: objx.bind(this.backToNormal, this)
		});
	},
	
	dragAcceptable: function () {
		
		this.element.addClass("droppable-accept");

	},
	
	backToNormal: function () {

		this.element.removeClass("droppable-accept");

	}
	
});

objx.provides("IODroppable");
var IODraggable = function(el, options, data) {
	// set the element
	var element = $(el);

	if(!options) { options = {}; }

	options.revert = 'invalid'; 	// FIXME https://iome.acunote.com/projects/9015/tasks/520 test this
	options.opacity = 0.6;

	element.draggable(options);

	if(data) { element.data("data", data); }	// FIXME https://iome.acunote.com/projects/9015/tasks/520 test this
};

objx.provides("IODraggable");
objx.requires("objx.Class", "IOHappeningTicker")
	.requires("IOHappeningManager", "IOHappeningTicker");

var IOHappeningTicker = objx.Class(IOControl, {
	
	updateDelay: 15000,
	counter: 0,
	happeningsToShow: 3,
	initialHappeningsToShow: 0,
	animate: true,
	
	created: function() {
		
		// create a happening manager to get the stories from...
		this.happeningManager = new IOHappeningManager();
		this.happeningManager.onItem(objx.bind(this.happeningManager_onItem, this));
		
		// schedule the first get (to allow a few seconds for the page to become functional)
		this.scheduleNextItem();
		
	},
	
	// Called when a story has been loaded by the manager
	happeningManager_onItem: function(story) {
		
		if (story) {
		
			var _this = this;
			var li = $("<li/>").html(story.description);
			this.element.prepend(li);
			var height = li.height();
			li.hide();
			
			if (this.animate) {
				li.height("0");
				li.animate({height:height});
			} else {
				li.show();
			}

			if (this.element.children().length > this.happeningsToShow){
				this.element.children().eq(this.happeningsToShow).animate({opacity:"0"}, function(){ $(this).slideUp("slow", function(){ $(this).remove(); }); });
			}
			
		}
		
		// schedule the next one...
		this.scheduleNextItem();
		
	},

	// Schedules the next item
	scheduleNextItem: function() {
		
		if (!this.animate && this.counter >= this.initialHappeningsToShow-1) {
			this.animate = true;
		}
		
		// wait a bit and get the next item...
		window.setTimeout(objx.bind(this.getNextItem, this), (this.counter < this.initialHappeningsToShow-1) ? 250 : this.getUpdateDelay());
		
	},
	
	// Gets the next item
	getNextItem: function() {
		
		// tall the manager to get the next item
		this.happeningManager.getItem();
		
		// not the first time...
		this.counter++;
		
	},
	
	getUpdateDelay: function() {
		return (this.updateDelay * Math.random()) + 1000;
	},
	
	experience_click: function(el) {
		if (typeof IOHub != "undefined"){ IOHub.onExperienceSelected(this, el.id); }
	},
	
	offer_click: function(el) {
		if (typeof IOHub != "undefined"){ IOHub.onOfferSelected(this, el.id); }
	}
	
});

objx.provides("IOHappeningTicker");
objx.requires("objx.Class", "IOBigHappeningTicker")
	.requires("IOHappeningManager", "IOBigHappeningTicker");

var IOBigHappeningTicker = objx.Class(IOHappeningTicker, {
	
	updateDelay: 10000,
	happeningsToShow: 12
	
});

objx.provides("IOBigHappeningTicker");
objx.requires("IOControl", "IOFooter")
	.requires("IOService", "IOFooter")
	.requires("IOHappeningTicker", "IOFooter");

var IOFooter = objx.Class(IOControl, {

	created: function(elem, dontHandleHappeningTicker) {
		
		this.feedEl = $(".footer").find(".happening-feed").children("ul:first");
		this.feed = new IOHappeningTicker(this.feedEl);
		
		if (!dontHandleHappeningTicker && typeof IOHub != "undefined"){
			
			IOHub.onExperienceSelected(objx.bind(this.hub_experienceSelected, this));
			IOHub.onOfferSelected(objx.bind(this.hub_offerSelected, this));
			
		}
		
	},
		
	hub_experienceSelected: function(sender, id){
		IORedirect.toDetails(id);
	},
	
	hub_offerSelected: function(sender, id){
		IORedirect.toDetails(id);
	}

});

objx.provides("IOFooter");
objx.requires("IOPage", "IOLocationSelector");

var IOLocationSelector = objx.Class(IOControl, {
	
	location: IOEgg.location,
	newLocation: null,
	
	mapWidth: "800px",
	mapHeight: "400px",
	changedCallback: null,
		
	createMapPopup: function(){
		this.mapEl = $("<div/>").css({width:this.mapWidth,height:this.mapHeight}).appendTo(this.element);
		this.map = new IOMap(this.mapEl);
	},

	showMap: function(options, changedCallback){
		
		if (!this.map){
			this.createMapPopup();
		}
		
		this.onChanged = changedCallback;
		
		// clear map overlays
		this.map.resetOverlays();
		
		this.location = options.location ? options.location : this.location;
		this.map.setLocation(this.location, IOMapConstants.defaultZoom);
		
		IOModal.init(this.element, {
			width: this.mapWidth,
			height: parseInt(this.mapHeight, 10) + 40 + "px",
			controls: "OKCancel",
			onOk: objx.bind(this.modal_ok, this),
			okText: "Change location"
		});
		
		this.map.resetAttributes();
		
		if (options.setMarker){
			
			var position = new GLatLng(this.location.lat, this.location.lng);
			
			marker = this.map.createMarker(position, { 
				icon: this.map.createIcon(),
				title: "Drag me to change the location",
				draggable: true
			});
			
			this.map.map.addOverlay(marker);
			marker.enableDragging();
			
			GEvent.addListener(marker, "dragend", objx.bind(this.marker_drag, this, marker));
			
		}
	},
	
	round: function(num) {
		return Math.round(num*10000)/10000;
	},
	
	marker_drag: function(marker){
		
		var p = marker.getPoint();
		
		this.newLocation = {
			lat: this.round(p.lat()),
			lng: this.round(p.lng())
		};
		
	},
	
	modal_ok: function(){
		if (this.newLocation){
			this.onChanged(this.newLocation);
		}
		this.newLocation = null;
		IOModal.close();
	}

});

var IOLocationSelectorInstance = new IOLocationSelector(
	$("<div/>").addClass("location-selector").appendTo("body")
);

objx.provides("IOLocationSelector");
objx.requires("IOPage", "IOLocationBox");

var IOLocationBox = objx.Class(IOControl, {
	
	onLocationChanged: objx.event,
	onLocationPointerClicked: objx.event,
	
	created: function(el, location, type){
		
		this.location = location;
		
		this.experienceLocationPointerEl = $("<a/>").addClass("pointer").appendTo(this.element);
		this.experienceLocationPointerEl.click(objx.bind(this.experienceLocationPointerEl_click, this));

		if (typeof(type) != 'undefined') {
			this.experienceLocationPointerEl.css("background-image", "url("+IOPin.getPin(type).img+")");
		}
	},
	
	experienceLocationPointerEl_click: function(){
		
		this.onLocationPointerClicked();
		
	},
	
	locationSelector_locationSelected: function(location) {
		this.onLocationChanged(location);
	}

});

objx.provides("IOLocationBox");






objx.requires("objx.Class", "IOShareModal")
	.requires("IOEmailService", "IOShareModal")
	.requires("IOSMSService", "IOShareModal")
	.requires("IORedirect", "IOShareModal");

var IOShareModalClass = objx.Class({
	
	showModal: function( sharingInfo ) {
		this.sharingHelper = sharingInfo;
	
		this.shareBox = $("<div>").append(
					$("<h3>")
						.text("Share this " + this.sharingHelper.label + " with friends")
				); 
				
		var addThisEl = $("<a/>");
		this.shareBox.append(addThisEl);
		addthis.button(addThisEl.get(0),
				{
					//services_expanded: 'email,twitter,facebook,reddit,bleetbox'
				},
				{
					url: sharingInfo.getUrl(),
					title: sharingInfo.getTitle(),
					email_template: sharingInfo.getEmailTemplate(),
					templates: {
						twitter: '{{title}}: {{url}} #plotstar'
					}
				}
				);

		if (this.sharingHelper.sms) {
			this.shareBox.append(
				$("<p>").text("or"),
				$("<label>")
					.attr("for", "mobile-no")
					.text("Phone: "),
				$("<input>")
					.attr("id", "mobile-no")
					.attr("type", "text", "tabindex", "2")
			);
		}
	
	    IOModal.init(this.shareBox, {
	      width: "250px",
	      controls: "OKCancel",
	      onOk: objx.bind(this.sendSMS, this),
	      onCancel: objx.bind(this.removeShareModal, this),
	      okText: "Share"
	    });
  	},

	sendSMS: function() {
		
		var mobileNo = this.shareBox.find("#mobile-no").val();
		if( this.sharingHelper.sms && mobileNo ) {
			smsMessage = this.sharingHelper.getSMSMessage( mobileNo );
			var ioSMSService = new IOSMSService();
			ioSMSService.successStatus = this.sharingHelper.label + " shared with " + mobileNo + " successfully.";
			ioSMSService.send(smsMessage);
		}
		
		this.removeShareModal();
	},
	
	removeShareModal: function() {
		if (typeof(this.shareBox) !== 'undefined') { this.shareBox.remove(); }
		IOModal.close();
	}
	
});

var IOShareModal = new IOShareModalClass();
objx.provides("IOShareModal");
objx.requires("IOPage", "IOPlanEditorListItem")
	.requires("IOLocationBox", "IOPlanEditorListItem")
	.requires("IOLocationSelector", "IOPlanEditorListItem");

this.IOPlanEditorListItem = objx.Class(IOControl, {
	
	onItemChanged: objx.event, // (leg, index)
	onItemRemoved: objx.event, // (leg, index)
	
	bindEvents: function(){
		this.removeEl.click(objx.bind(this.removeEl_click, this));
		this.locationBox.onLocationChanged(objx.bind(this.locationBox_locationChanged, this));
		this.locationBox.onLocationPointerClicked(objx.bind(this.locationBox_locationPointerClicked, this));
	},
	
	created: function(el, leg, index){
		
		// save the index
		this.legIndex = index;
		this.legData = leg;
		
		this.element.data("leg", leg);
		
		this.createItem(leg);
		this.bindEvents();
		
	},
	
	createItem: function(leg){
		
		var _this = this;
		
		this.clearerEl = $("<div/>").addClass("clearer");
		
		this.planDetailsEl = $("<div/>").addClass("plan-details");
		this.planDetailsClearTimeEl = $("<a>clear</a>").hide();
		this.planDetailsTimeEl = $("<div/>").addClass("time highlight");
		this.planDetailsTimeHourEl = $("<span/>").addClass("hour");
		this.planDetailsTimeDividerEl = $("<span/>").text(":").addClass("divider");
		this.planDetailsTimeMinuteEl = $("<span/>").addClass("minute");
		
		this.when = leg.when || {};
				
		if (leg.when){
			if (leg.when.time){
				this.setTime(leg.when.time);
			}
		}
		
		this.planDetailsTimeEl.editable({
			type:"time",
			clearBy:this.planDetailsClearTimeEl,
			guideText:"Set Time",
			onSubmit:function(){ _this.planDetailsTimeEl_submit(); },
			onEdit:function(){ _this.planDetailsTimeEl_edit(); },
			onCancel:function(){ _this.planDetailsTimeEl_cancel(); },
			onClear:function(){ _this.planDetailsTimeEl_clear(); }
		});
				
		this.legData.when = leg.when || {};
		
		this.planDetailsEl.append(this.planDetailsTimeEl);
		this.planDetailsEl.append(this.planDetailsClearTimeEl);
					
		this.experienceListEl = $("<ul/>").addClass("experiences");
		this.experienceListItemEl = $("<li/>");
		
		this.experienceTypeEl = $("<div/>").addClass("type");
		
		this.experienceLocationEl = $("<div/>").addClass("location");
		this.locationBox = new IOLocationBox(this.experienceLocationEl, null, leg.type);

		this.experienceDragEl = $("<div/>").addClass("drag");
		
		this.experienceTitleEl = $("<h4/>")
			.addClass("title")
			.html(leg.title)
			.editable({
				onSubmit: objx.bind(this.experienceTitle_submit, this),
				guideText: "Enter a title"
			});
		
		this.experienceDescEl = $("<p/>")
			.addClass("description")
			.html(leg.description)
			.editable({
				onSubmit: objx.bind(this.experienceDesc_submit, this),
				type: "textarea",
				guideText: "Enter a description"
			});
		
		this.experienceInfoEl = $("<div/>").addClass("info")
			.append(this.experienceTitleEl, this.experienceDescEl);
		
		this.experienceListItemEl.append(this.experienceTypeEl, this.experienceLocationEl, this.experienceInfoEl);
		this.experienceListEl.append(this.experienceListItemEl);
			
		this.dragEl = $("<a/>").addClass("handle");
		this.removeEl = $("<a/>").addClass("item-remove remove-button-small");
		
		this.element.append(this.dragEl, this.planDetailsEl, this.experienceListEl, this.removeEl, this.clearerEl);
		
	},
	
	removeItem: function(){
		//if (confirm("Are you sure you want to remove this item from your plan?")){
			var _this = this;
			this.onItemRemoved(this.legData, this.legIndex);
			this.element.slideUp("fast", function(){
				_this.element.remove();
			});			
		//}
	},
	
	setTime: function(time){
		this.when.time = time;
		this.planDetailsTimeEl.empty().append(
			this.planDetailsTimeHourEl.html(IOMath.pad(time.hour,2)),
			this.planDetailsTimeDividerEl,
			this.planDetailsTimeMinuteEl.html(IOMath.pad(time.minute,2))
		);
		this.legData.when.time = {
			hour: time.hour,
			minute: time.minute
		};
		this.onItemChanged(this.legData, this.legIndex);
	},
	clearTime: function(){
		this.legData.when.time = null;
		this.onItemChanged(this.legData, this.legIndex);
	},
	
	setLocation: function(location){
		this.legData.location = location;
		
		this.onItemChanged(this.legData, this.legIndex);
	},
	
	removeEl_click: function(){
		this.removeItem();
	},
	
	planDetailsTimeEl_submit: function(){
		var time = {
			hour: parseInt(this.planDetailsTimeEl.text().substring(0,2), 10),
			minute: parseInt(this.planDetailsTimeEl.text().substring(2,4), 10)
		};
		this.planDetailsClearTimeEl.hide();
		this.setTime(time);
	},
	planDetailsTimeEl_edit: function(content){
		if (this.legData.when.time){
			this.planDetailsClearTimeEl.show();
		}
	},
	
	planDetailsTimeEl_cancel: function(){
		this.planDetailsClearTimeEl.hide();
	},
	planDetailsTimeEl_clear: function(){
		this.clearTime();
	},
	locationBox_locationChanged: function(location){
		this.setLocation(location);
	},
	locationBox_locationPointerClicked: function(){
		IOLocationSelectorInstance.showMap({
			setMarker: true,
			draggable: true,
			location: this.legData.location
			}, objx.bind(this.locationBox.locationSelector_locationSelected, this.locationBox));
	},
	experienceTitle_submit: function(){
		this.legData.title = this.experienceTitleEl.data('editable.current');
		this.onItemChanged(this.legData, this.legIndex);
	},
	experienceDesc_submit: function(){
		this.legData.description = this.experienceDescEl.data('editable.current');
		this.onItemChanged(this.legData, this.legIndex);
	}
});

objx.provides("IOPlanEditorListItem");
objx.requires("IOPage", "IOPlanEditorList")
	.requires("IOPlanEditorListItem", "IOPlanEditorList");

var IOPlanEditorList = objx.Class(IOControl, {
	
	onItemChanged: objx.event, // (leg, index)
	onItemRemoved: objx.event, // (leg, index)
	onItemsReordered: objx.event, // (legs)
	onPlanLoaded: objx.event,
	
	listItems: [],
	
	created: function(){
		
		this.addLegEl = this.element.find(".add-leg");
		
	},
	
	clearLegs: function(){
		this.element.find(".plan-item").remove();
	},
	
	setLegs: function(legs){
		
		this.clearLegs();
		
		objx(legs).each(objx.bind(function(leg, index){
			
			this.addLeg(leg, index);
			
		}, this));
		
		this.element.sortable({
			update: objx.bind(this.list_sorted, this),
			placeholder: "plan-item-highlight",
			items: "li.plan-item",
			handle: ".handle",
			tolerance: "pointer",
			axis: "y",
			revert: 100
		});
		
		this.onPlanLoaded();
		
	},
	
	addLeg: function(leg, index){
		
		var legEl = $("<li/>").addClass("plan-item");
					
		legEl.insertBefore(this.addLegEl);
					
		var listItem = new IOPlanEditorListItem(legEl, leg, index);
				
		listItem.onItemChanged(objx.bind(this.item_onItemChanged, this));
		listItem.onItemRemoved(objx.bind(this.item_onItemRemoved, this));
		
		this.listItems.push(listItem);
	
	},
	
	list_sorted: function(event, ui){
		var legs = [];
		var item = null;
		
	    this.element.children("li.plan-item").each(function(i){
	    	leg = $(this).data("leg");
			if (leg){
				leg.order = i;
				legs.push(leg);
			}
	    });
					
	    this.onItemsReordered(legs);
	
	},
	
	item_onItemChanged: function(){
		this.onItemChanged.apply(this, arguments);
	},
	item_onItemRemoved: function(){
		this.onItemRemoved.apply(this, arguments);
	}
	
});

objx.provides("IOPlanEditorList");
objx.requires("IOPage", "IOPlanEditor")
	.requires("IOShareModal", "IOPlanEditor")
	.requires("IOPlanEditorList", "IOPlanEditor")
	.requires("jquery.editable", "IOPlanEditor")
	.requires("IOPlanDataManager", "IOPlanEditor")
	.requires("IOPlanSharingInfo", "IOPlanEditor")
	.requires("jquery.uuid", "IOPlanEditor");

// optional control
var IOStarredItemsList = IOStarredItemsList || null;

var IOPlanEditor = objx.Class(IOControl, {
	
	onPlanChanged: objx.event, // ( IOPlan plan-data ) - triggered when a plan has changed
	onPlanDeleted: objx.event, // ( Number plan-id ) - triggered when a plan has been deleted
	
	guideText:{
		planDate: "Enter a date for your plan"
	},
	
	findElements: function() {
	
		this.planListEl = this.element.find("ol.plan-items");
		this.starredItemsListEl = this.element.find(".bucket");
		this.planHeaderEl = this.element.find(".editor-header");
		this.planTitleEl = this.element.find(".editor-header h3");
		this.planDateEl = this.element.find(".editor-header small");
    	this.planDateClearEl = $("<a/>").text("clear").addClass("clear-button");
		this.planViewLinkEl = this.element.find(".view-plan");
		this.orderPlanLinkEl = this.element.find(".order-plan");
		this.sharePlanLinkEl = this.element.find(".share-plan");
		this.deletePlanLinkEl = this.element.find(".delete-plan");
		this.addNewLegLinkEl = this.element.find(".add-leg").children("a");
		this.privateEl = this.element.find(".private-plan");
		
	},
	
	bindEvents: function() {
		
		if (this.planList) {
			this.planList.onItemRemoved(objx.bind(this.planList_onItemRemoved, this));
			this.planList.onItemChanged(objx.bind(this.planList_onItemChanged, this));
			this.planList.onPlanLoaded(objx.bind(this.planList_onPlanLoaded, this));
			this.planList.onItemsReordered(objx.bind(this.planList_onItemsReordered, this));
		}
		if (this.orderPlanLinkEl) { this.orderPlanLinkEl.click(objx.bind(this.orderPlanLinkEl_click, this)); }
		if (this.sharePlanLinkEl) { this.sharePlanLinkEl.click(objx.bind(this.sharePlanLinkEl_click, this)); }
		if (this.addNewLegLinkEl) { this.addNewLegLinkEl.click(objx.bind(this.addNewLegLinkEl_click, this)); }
		if (this.deletePlanLinkEl) { this.deletePlanLinkEl.click(objx.bind(this.deletePlanLinkEl_click, this)); }
		
		if (this.starredItemsList) {
			this.starredItemsList.onItemAdded(objx.bind(this.starredItemsList_onItemAdded, this));
		}
		
		var _this = this;
		
		if (this.planDateEl) {
			this.planDateEl
				.editable({
					type:"date",
					submit:"ok",
					cancel:"cancel",
					clearBy:this.planDateClearEl,
					guideText: this.guideText.planDate,
					onSubmit:function(){ _this.planDateEl_submit(); },
					onEdit:function(){ _this.planDateEl_edit(); },
					onCancel:function(){ _this.planDateEl_cancel(); },
					onClear:function(){ _this.planDateEl_clear(); }
				});
		}
				
	},

	created: function() {

		this.findElements();

		this.element.show();
		
		if (this.planListEl) { this.planList = new IOPlanEditorList(this.planListEl); }
		
		if (IOStarredItemsList && this.starredItemsListEl) {
			this.starredItemsList = new IOStarredItemsList(this.starredItemsListEl);
		}
		
		this.privateCheckbox = $("<input/>")
									.addClass("private-plan-indicator")
									.attr({
										"type": "checkbox",
										"checked": false,
										"id": "private-plan-cb"
									})
									.change(objx.bind(this.privateCheckbox_changed, this));
		
		var privateLabel = $("<label/>")
									.addClass("private-plan-indicator")
									.attr("for", "private-plan-cb")
									.text("Private");

		if (this.privateEl) {	this.privateEl.append(privateLabel, this.privateCheckbox); }
		
		this.bindEvents();
		
	},
	
	setPlan: function(plan) {
		
		var $this = this;
		
		this.planManager = new IOPlanDataManager(plan);
				
		this.planTitleEl
			.editable("destroy")
			.text(plan.title || "")
			.editable({
				onSubmit:function(){
					$this.planManager.setTitle($this.planTitleEl.data('editable.current'));
					$this.raisePlanChangedEvent();
				},
				guideText:"Enter a title for your plan"
			});

		
		var date = new Date();
		var niceDate = null;
		
		if (typeof(plan.start) !== "undefined" && plan.start !== null) { date.setTime(plan.start);
			niceDate = IODateTime.toNiceDate(date);
			this.planDateEl.html(niceDate).removeClass("guide-text").attr("id","plan-date-"+plan.id);
		} else {
			this.planDateEl.html(this.guideText.planDate).addClass("guide-text");
		}

		this.currentPlan = plan;
		
		this.planHeaderEl.append(this.planDateClearEl);
		
		this.planList.setLegs(plan.legs);
				
		var priv = this.planManager.isPrivate();
		this.privateCheckbox.attr("checked", priv);
		this.setPlanViewLink(priv, this.planManager.getPrivateKey());
		
	},
	
	privateCheckbox_changed: function() {
		
		var isPrivate = this.privateEl.children("input:checkbox:checked").val();
		var pkey = isPrivate ? $.uuid() : null;
		this.planManager.setPrivateKey(pkey);
		this.setPlanViewLink(pkey);
		this.raisePlanChangedEvent();
		
	},

	setPlanViewLink: function(pkey) {
		this.planViewLinkEl.attr({
			href: IORedirect.getPlanViewerLink(this.planManager.getPlanId(), this.planManager.getPrivateKey()),
			target: "_blank"
		});
	},	
	
	addBlankLeg: function(){
		this.addItemToPlan(
			{
				"when":{},
				"title":null,
				"description":null,
				"experienceId":null,
				"location":IOEgg.location,
				"id":null,
				"type": 0
			}
		);
		this.raisePlanChangedEvent();
	},
	
	setDate: function(date){
		this.planManager.setStart(date.getTime());
		this.raisePlanChangedEvent();
	},
	clearDate: function(){
		this.planManager.setStart(null);
		this.raisePlanChangedEvent();
	},
	
	createLegFromStar: function(star){		
		var leg = this.planManager.createLeg(star);
		this.planList.addLeg(leg);
		this.raisePlanChangedEvent();
	},

	planDateEl_submit: function(){
		this.planDateClearEl.hide();
		this.setDate(IODateTime.fromNiceDate(this.planDateEl.text()));
	},
	planDateEl_edit: function(plan){
    // FIXME: on new it's hidden, on editing it's displayed but does nothing, hidden for now
    // if (plan.start){
    //  this.planDateClearEl.show();
    // }

		// FIXME: [mehmet] these events are used for checking when a planDateEl looses focus 
		// (in order to end editing before starting to a edit of another element)
		this.planDateEl.children().bind('blur', objx.bind( this.planDateEl_blur, this));
		this.planDateEl.children().bind('focus', objx.bind( this.planDateEl_focus, this));
	},
	
	planDateEl_blur: function(){
		// either day, month or year element lost the focus
		this.hasPlanDateFocus = false;
		// wait for 100ms (be sure that sibling receives focus if something else wasn't clicked) and check if editing should be terminated 
		setTimeout(objx.bind(function(event){
			if(!this.hasPlanDateFocus) {
				// cancel editing of planDetailsTimeEl 
				this.planDateEl.data('editable.options').toNonEditable(this.planDateEl, false);
			}
		},this), 100);
	},
	
	planDateEl_focus: function(){
		// either day, month or year element gained the focus
		this.hasPlanDateFocus = true;
	},

	planDateEl_cancel: function(){
    	this.planDateClearEl.hide();
	},
	planDateEl_clear: function(){
		this.clearDate();
	},

	addItemToPlan: function(leg) {
		
		this.planManager.addLeg(leg);
		this.planList.addLeg(leg, leg.order);
		
	},
	
	setStarredItems: function(stars) {
	
		this.starredItemsList.setItems(stars);
		
	},
	
	planList_onItemChanged: function(leg, index) {
		
		this.planManager.changeLeg(leg, index);
		
		// inform that we have changed the plan
		this.raisePlanChangedEvent();
		
	},
	
	planList_onItemRemoved: function(leg, index) {
		
		this.planManager.removeLegByIndex(index);
		
		// inform that we have changed the plan
		this.raisePlanChangedEvent();
		
	},
	
	planList_onItemsReordered: function(legs) {
		
		this.planManager.orderLegs(legs);
		this.planList.setLegs(legs);

		// inform that we have changed the plan
		this.raisePlanChangedEvent();
		
	},
	
	planList_onPlanLoaded: function(){
		this.planList.element.show();		
	},
	
	starredItemsList_onItemAdded: function(star){
		
		this.createLegFromStar(star);
		
	},
	
	orderPlanLinkEl_click: function(){
		this.planManager.orderLegsByTime();
		
		var p = this.planManager.data().obj();
		this.setPlan(p);
		// inform that we have changed the plan
		this.raisePlanChangedEvent();
	},
	
	sharePlanLinkEl_click: function(){
		IOShareModal.showModal( new IOPlanSharingInfo(this.planManager.data().obj()) );
	},
	
	deletePlanLinkEl_click: function() {
		
		if (confirm("Are you sure you want to delete this plan?")) {
			
			var planId = this.planManager.getPlanId();
		
			// delete the plan
			IOPlan.del(planId);
			
			// raise the plan deleted event
			this.onPlanDeleted(planId);
			
		}
		
		return false;
		
	},
	
	addNewLegLinkEl_click: function(){
		this.addBlankLeg();
	},
	
	raisePlanChangedEvent: function() {
		this.onPlanChanged(this.planManager.data().obj());
	}
});

objx.provides("IOPlanEditor");
objx.requires("IOControl", "IOPlansOverview");

var IOPlansOverview = objx.Class(IOControl, {
	
	created: function(){
		
		this.noPlansElement = $("<div>You don't have any plans, to make one go back to the <a href=\"/discover\">discover</a> page and find stuff you want to do.</div>").attr("id","no-plans").addClass("no-plans").hide();
		
		this.element.append(this.noPlansElement);
		
	},
	
	showPlans: function(plans) {
		
		if (plans && plans.length > 0) {
			
			this.noPlansElement.hide();
		
			var el = this.element;
			this.plansList = $("<ol />").addClass("plans");
			var plansList = this.plansList;
			
			el.append(plansList);
		
			objx(plans).each(objx.bind(function(plan){
			
				var planDetails = $("<div/>").addClass("plan-details");
				var planLegs = $("<ol/>");
				var planOptions = $("<div/>").addClass("plan-options");
				var planHeader = $("<div/>").addClass("plan-header");
				var planItem = $("<li/>").addClass("plan")
					.append(planHeader)
					.append(planDetails
						.append(planLegs)
					)
					.append(planOptions);
			
				var viewLink = "/plans/" + plan.id + "/view";

				if (plan.privateKey) {
					viewLink += "?pkey=" + plan.privateKey;
				}
			
				planHeader.append("<a id='edit-plan' class='edit-link' title='Click here to modify this plan' href='/discover#mode=edit&planId=" + plan.id + "'>Edit</a>")
					.append($("<h3/>").html("<a href='" + viewLink + "' title='Click here to view this plan'>" + IOPlanHelper.getPlanTitle(plan) + "</a>"));
			
				//var deletePlan = $("<a/>").text("Delete").click(objx.bind(this.planDelete_click, this, plan, planItem));
				//var viewPlan = $("<a/>").text("View").attr("href", "/plans/" + plan.id + "/view");
			
				// TODO: promote this functionality to IORedirect (or similar)
				//var editPlan = $("<a/>").text("Edit").attr("href", "/discover#mode=edit&planId=" + plan.id);
			
				//planOptions.html("<a id='edit_plan' href='/discover#mode=edit&planId=" + plan.id + "'>Edit</a>, <a href='" + viewLink + "'>view</a> or <a id='delete_plan' href=''>delete</a> this plan.")
			
				planOptions.html("<a id='delete_plan' href='#' title='Click here to delete this plan' >Delete plan </a>" );
			
			
				planOptions.find("#delete_plan").click(objx.bind(this.planDelete_click, this, plan, planItem));
			
				//planOptions.append(editPlan, $("<span>,&nbsp;</span>"), viewPlan, $("<span>&nbsp;or&nbsp;</span>"), deletePlan, $("<span>&nbsp;this plan</span>"));
			
				var date = new Date();
			
				if (plan.legs.length === 0) {
				
					planLegs.append("<li><strong>There are no items in this plan</strong></li><li><a href=\"/discover\">Discover</a> things to add</li>");
				
				} else {
			
					objx(plan.legs).each(function(leg){
					
						date.setTime(plan.start);
						if (leg.when.time) {
							date.setHours(leg.when.time.hour);
							date.setMinutes(leg.when.time.minute);
						}
						var dateText = plan.start ? IODateTime.toNiceDate(date) : "";
						var timeText = plan.start ? IODateTime.toNiceTime(date) : "";
						if (dateText !== "" && timeText !== ""){
							timeText += " - ";
						}
				
						planLegs.append(
							$("<li/>").append($("<h4/>").text(IOPlanHelper.getLegTitle(leg)))
										.append($("<p/>").html(timeText + dateText))
						);
					
					});
			
				}
			
				plansList.append(planItem);
			
			}, this));
		
		} else {
			
			this.noPlansElement.show();
			
		}
		
	},
	
	planDelete_click: function(plan, el) {
		
		if (confirm("Are you sure you want to delete this plan?")) {
			
			IOPlan.del(plan.id);
			
			var thisControl = this;
			
			//IOPlan.del(plan.id);
			
			el.animate({opacity:0}, function(){ 
				
				$(this).animate({width:0}, function(){ 
					
					$(this).remove(); 
					
					if (thisControl.plansList.children().size() === 0) {
						thisControl.noPlansElement.fadeIn();
					}
					
				});
				
			});
			
		}
		
		return false;
		
	}
	
});

objx.provides("IOPlansOverview");
objx.requires("IOControl", "IOAddPlanDropDown");

var IOAddPlanDropDown = objx.Class(IOControl, {
	
	onPlanUpdated: objx.event,
	
	created: function() {
		// TURNED OFF
		return;
	},
	
	updateMyPlans: function(plans) {
		// TURNED OFF
		return;
	},
	
	addToPlan: function() {
		// TURNED OFF
		return;
	},
	
	updatePlan: function(planData) {
		// TURNED OFF
		return;
	}
	
});

objx.provides("IOAddPlanDropDown");
var IOAutoPlan = objx.Class(IOControl, {

	categories: {
	
		indian: {
			name: "Indian Restaurant",
			query: "cuisinegrp:indian"
		},
		drinking: {
			name: "Drinks",
			query: "cat:drinking"
		},
		casino: {
			name: "Casino",
			query: "gamble:casino"
		},
		restaurants: {
			name: "Restaurant",
			query: "cat:restaurants"
		},
		clubbing: {
			name: "Club",
			query: "cat:clubs"
		},
		cafe: {
			name: "Café",
			query: "cat:cafe"
		},
		theatre: {
			name: "Theatre",
			query: "cat:theatre"
		},
		bowling: {
			name: "Bowling",
			query: "sport:bowling"
		},
		amusement: {
			name: "Amusement",
			query: "cat:amusement_park"
		},
		snooker: {
			name: "Snooker Hall",
			query: "sport:snooker"
		},
		music: {
			name: "Music Event",
			query: "cat:music"
		},
		comedy: {
			name: "Comedy",
			query: "cat:comedy"
		}

	},
	
	getCategory: function(cat){
		return this.categories[cat];
	},
	
	plans: [
	
		{
			title: "Boy's night out",
			legs: [
				"drinking",
				"indian",
				"drinking",
				"casino"
			]
		},
		{
			title: "Girl's night out",
			legs: [
				"restaurants",
				"drinking",
				"clubbing"
			]
		},
		{
			title: "Romantic Weekend",
			legs: [
				"cafe",
				"theatre",
				"restaurants",
				"drinking"
			]
		},
		{
			title: "Comedy night",
			legs: [
				"drinking",
				"comedy"
			]
		},
		{
			title: "Play day",
			legs: [
				"bowling",
				"cafe",
				"amusement",
				"snooker"
			]
		},
		{
			title: "Music night",
			legs: [
				"drinking",
				"music",
				"clubbing"
			]
		}
		
	],
	
	created: function(el, planService){
		
		this.planService = planService;
		this.planService.onAutoPlanLoaded(objx.bind(this.autoplan_loaded, this));
		this.geocoderService = new IOFullPostcodeGeocoderService();
		
		IOPlan.onCreated(objx.bind(this.plan_created, this));
		IOPlan.onSaved(objx.bind(this.plan_saved, this));
		
		this.geocoderService.onCertainOption(objx.bind(this.certainOption_loaded, this));
		this.geocoderService.onOptions(objx.bind(this.options_loaded, this));
		
		this.planTypeEl = $("<select/>");
		
		for (var i=0, il=this.plans.length; i<il; i++){
			
			this.planTypeEl.append($("<option/>").text(this.plans[i].title).val(i));
			
		}
		
		this.locationEl = $("<input type='text'/>").addClass("input-type-text"); //.clearingInput({text:"e.g. London, Ipswich, SE16 etc."});;
		
		this.goButtonEl = $("<input type='button'/>").addClass("inspire-button").val("Inspire me");
		this.resultsEl = $("<div/>").addClass("autoplan-results").hide();
		this.headingEl = $("<div/>").addClass("auto-plan-heading auto-plan-unused").append(
			$("<h2/>").text("Need inspiration? Try a random plan"),
			$("<div/>").addClass("autoplan-options")
				.append(
					$("<label/>").addClass("option-header").text("What do you want:"),
					this.planTypeEl,
					$("<label/>").addClass("option-header").text("near"),
					this.locationEl,
					this.goButtonEl)
		);
		
		this.element.append(
			this.headingEl
		);
		
		this.element.append(
				this.resultsEl
		);
		
		this.goButtonEl.click(objx.bind(this.goButtonEl_click, this));
		
		$(".input-type-text").keyup(objx.bind(function(event){
		  if(event.keyCode == 13){
		    this.goButtonEl.click();
		  }
		}, this));
		
	},
	
	showResults: function(options, index){
	
		this.resultsEl.show();
		this.headingEl.removeClass("auto-plan-unused");
	
		var optionsEl = null;
	
		optionsEl = $("<ul/>").addClass("results");
		
		if (options.length === 0) {
			resultsElement = $("<li class='no-plans'><p>Oops, we don't have any ideas.  Try picking something else.</p></li>");
			
			window.setTimeout(function(){

				resultsElement.hide().appendTo(optionsEl).fadeIn();
				
			}, 500);
			
		}
		
		
		
		objx(options).each(objx.bind(function(option, x){
			
			option.description = option.shortDescription;
			option.when = {};
			
			var resultsElement = $("<li/>").addClass("result").addClass("experience-type-" + option.type).append(

				$("<div/>").append(

					$("<input type='radio' name='autoplan-leg-option-" + index + "' id='autoplan-leg-option-" + index + "-" + x + "' />")
						.addClass("select-button")
						.data("leg",option)
						.click(function(){

								var $this = $(this);

								if ($this[0].checked) {
									$this.parents(".results").find(".checked-box").removeClass("checked-box");
									$this.parent().addClass("checked-box");
								} else {
									$this.parent().removeClass("checked-box");
								}

								return true;

						})
						.addClass("select-button").attr("name","autoplan-leg-option-" + index).attr("id","autoplan-leg-option-" + index + "-" + x),

					$("<label/>").addClass("label").text(option.title).attr("for", "autoplan-leg-option-" + index + "-" + x),
					$("<span/>").text(option.details.address),
					$("<a/>").attr("href", "/experiences/" + option.experienceId).attr("target", "_blank").text("View details").addClass("view-auto-plan-details")
				)
				
			);
			
			//optionsEl.append(resultsElement);
			
			optionsEl.css("overflow", "hidden");
			
			window.setTimeout(function(){
				
				resultsElement.css("position", "relative").css("left", "1000px").css("opacity", "0").appendTo(optionsEl).animate({ opacity: 1, left: "0px" })
				
			}, 500 * (x+1));
			
		}, this));
			
		this.resultsListEl.children("li").eq(index).append(optionsEl);
		
		window.setTimeout(objx.bind(function(){
			this.resultsListEl.children("li").eq(index).find(".busy").hide();
		}, this), 1000);
		
	},
	
	generateAutoPlan: function(data, count){
		
		var selectedPlanIndex = parseInt(this.planTypeEl.val(), 10);
		
		this.resultsListEl = $("<ol/>").appendTo(this.resultsEl);
		
		var categoryListEl = null;
		
		for (var i=0, il=this.plans[selectedPlanIndex].legs.length; i<il; i++){
			
			categoryListEl = $("<select/>");
			categoryListEl.change(objx.bind(this.categoryListEl_change, this, categoryListEl, i, selectedPlanIndex, data, count));
			
			for (var property in this.categories){
				categoryListEl.append($("<option/>").text(this.categories[property].name).val(property));
			}
			
			categoryListEl.children("[value="+this.plans[selectedPlanIndex].legs[i]+"]").attr("selected","selected");

			this.resultsListEl.append(
				$("<li/>").addClass("results-section")
					.append(
						$("<span/>").addClass("sub-cat").html("Pick a "),
						categoryListEl,
						$("<input type='button' value='Shuffle' class='shuffle-button' />").click(objx.bind(this.categoryListEl_change, this, categoryListEl, i, selectedPlanIndex, data, count)),
						$("<img class=\"busy\" src=\"/img/loaders/ajax-loader(4).gif\" />"))
			);		
			
			this.planService.generateAutoPlan(data, this.getCategory(this.plans[selectedPlanIndex].legs[i]).query, count, i);		
			
		}
		
		this.savePlanButton = $("<input type='button' value='Make a plan...' />").click(objx.bind(this.savePlan_click, this));
		this.resultsEl.append(

			$("<div class='clear-menu'></div>"),

			$("<div/>").addClass("save-plan-button menu-bar").append(
				$("<p>Pick some places from the options above and click 'Make a plan...'</p>"),
				this.savePlanButton)

		);
		
	},
	
	goButtonEl_click: function(){
		
		if (this.locationEl.val() == "") {
		
			alert("You must enter a location before we can inspire you");
		
		} else {
		
			this.goButtonEl.attr("disabled", "disabled");
		
			this.resultsEl.empty();
			this.geocoderService.find(this.locationEl.val());
		
		}
		
	},
	
	categoryListEl_change: function(categoryListEl, index, selectedPlanIndex, data, count) {
		
		this.resultsListEl.children("li").eq(index).find(".results").animate({ marginLeft: "-1000px", opacity: 0 }, function(){ $(this).remove(); });
		this.resultsListEl.children("li").eq(index).find(".busy").show();
		this.planService.generateAutoPlan(data, this.getCategory(categoryListEl.val()).query, count, index);	
		
	},
	
	autoplan_loaded: function(data, index){
		var legs = {options:data};
		this.showResults(data, index);
		this.goButtonEl.removeAttr("disabled");
	},
	
	certainOption_loaded: function(data){
		this.generateAutoPlan(data, 3);
	},
	
	options_loaded: function(data){
		// TODO: handle multiple location options
	},
	
	savePlan_click: function(){
		this.savePlanButton.attr("disabled", "disabled");
		IOPlan.create();
	},
	
	plan_created: function(response){
		response.title = this.planTypeEl.children(":selected").text();
		this.resultsEl.find(":checked").each(function(){
			response.legs.push($(this).data("leg"));
		});
		IOPlan.save(response.id, response);
	},
	
	plan_saved: function(plan){
		location.href = "/discover#mode=edit&planId=" + plan.id;
	}
	
});

objx.provides("IOAutoPlan");
objx.requires("IOPage", "IOStarButton")
	.requires("IOStarDataManager", "IOStarButton");


var getItemId = function(item) {
	return item.refId || item.experienceId || item.voucherId || null;
};

var createStarId = function(item) {
	var itemId = getItemId(item); 
	if(itemId)
		{return "star_" + itemId.replace(/[,+%.]/g, '_');}
	return 'star_any';
};

var IOStarButton = objx.Class(IOControl, {

	// handlers
	onToggle: objx.event,
		
	created: function(element, data) {

		var starData = IOStarData;
		this.type = this.getType(data);
		this.refId = getItemId(data);
		this.starId = createStarId(data);
		this.data = data;
		this.starred = starData.isStarred(this.type, this.refId);

		this.starEl = $("<a/>")
			.addClass("star")
			.addClass(this.starId)
			.nolink()
			.click(objx.bind(this.toggle, this));
		var starEl = this.starEl;
		
		if (this.starred) {
			
			// already starred
			starEl.attr("title", "Unstar this item")
				.addClass("starred")
				.text("  ");
			
		} else {
			
			// not starred
			starEl.attr("title", "Star this item")
				.addClass("non-starred")
				.text("  ");
			
		}

		// if star-callback defined, apply it to all occurences of star element
		if (typeof IOStar_callback !== 'undefined') { 
			this.onToggle(objx.bind(IOStar_callback, this)); 
		}
		
		this.element.append(starEl);
		
	},
	
	toggle: function() {

		// if star-callback defined, check if ui element is starred
		if (typeof IOStar_callback !== 'undefined') {
			this.starred = this.element.find(":first-child").is(".starred");
		}
		
		var itemAffected = null;
				
		if (this.starred) {
			this.unstar();
			this.starred = false;
		} else {
			itemAffected = this.star();
			this.starred = true;
		}
		
		// onToggle pass back to onToggle method
		this.onToggle(this.starId, this.starred, itemAffected);
	},
	
	star: function() {

		// affect all page elements with same star-id class
		$("."+this.starId)
			.removeClass("non-starred")
			.addClass("starred");
			
		return IOStarData.star(this.type, this.data);
		
	},

	unstar: function() {
		
		$("."+this.starId)
			.removeClass("starred")
			.addClass("non-starred");

		IOStarData.unstar(this.type, this.refId);

	},
	
	getType: function(item) {
		
		if (item.experienceId)
			{return IOItemType.experience;}
		else if (item.voucherId)
			{return IOItemType.offer;} 
		else
			{return item.type || IOItemType.unknown;}
	}
	
});

objx.provides("IOStarButton");
// http://apiwiki.iogloballtd.com/mediawiki/index.php/IOMapInfoHandler

objx.requires("objx.Class", "IOMapInfoHandler");

var IOMapInfoHandler = objx.Class({
	
	onOpened: objx.event,
	onClosed: objx.event,
	
	init: function(addPlanDropDown) {
		
		this.addPlanDropDown = addPlanDropDown;
	
	},
	
	// opens the popup on the map
	openPopup: function(map, content, position) {

		// use google maps api and display popup
		map.openInfoWindowHtml(position, content);
		
	},
	
	// when overridden in a derived class shows a popup for the given data object
	/* virtual */ showPopup: function(map, data) {
		throw "You must override the showPopup class in classes that derive IOMapInfoHandler.  See http://apiwiki.iogloballtd.com/mediawiki/index.php/IOMapInfoHandler";
	}
	
});

objx.provides("IOMapInfoHandler");
// http://apiwiki.iogloballtd.com/mediawiki/index.php/IOExperiencePopupHandler

objx.requires("IOMapInfoHandler", "IOExperienceMapInfoHandler")
	.requires("IOStarButton", "IOExperienceMapInfoHandler")
	.requires("IOExperienceSharingInfo", "IOExperienceMapInfoHandler")
	.requires("IOShareModal", "IOExperienceMapInfoHandler");

var IOExperienceMapInfoHandler = objx.Class(IOMapInfoHandler, {
	
	onDetailsRequest: objx.event,
	
	hide: function() {
		if (this.infoPaneEl) {
			this.infoPaneEl.hide();
		}
	},
	
	showPopup: function(map, data, options) {

		for (var option in options){
			this[option] = options[option];
		}
		
		if (!this.infoPaneEl){
			this.infoPaneEl = $(".info-pane");
		}
		
		this.data = data;
		
		var details = $("<div/>").addClass("details");
		var controls = $("<div/>").addClass("controls");
		var star = $("<div/>").addClass("star");
		var extra = $("<div>").addClass("extra-details");
		
		extra.append(
			$("<a/>")
				.text("Street View")
				.nolink()
				.click(objx.bind(this.streetview, this, data)),
			$("<a/>")
				.addClass("share")
				.text("Share")
				.nolink()
				.click(objx.bind(this.share, this, data))	
		);
		
		this.addPlanDropDown = null;
		if ( null !== this.addPlanDropDown && null !== this.addPlanDropDown.addToPlansSelectEl) {
			this.addPlanDropDown.data = this.data;
			extra.append(this.addPlanDropDown.addToPlansSelectEl);
		}
		
		details.append(
			$("<h4/>").addClass("title").text(data.title),
			star);
			
		if (data.voucherCount) {
			details.append(
				$("<div/>").addClass("offer")
			);
		}
		
		var dataDetails = data.details;
		
		if (!dataDetails) {
			dataDetails = {
				phoneNumber: "",
				address: "",
				postcode: ""
			};
		}
		
		details.append(
			$("<small/>").addClass("description").text(data.shortDescription),
			$("<p/>").addClass("phone-number").text(dataDetails.phoneNumber),
			$("<p/>").addClass("address").text(dataDetails.address ? dataDetails.address + " " + dataDetails.postcode : ""),
			extra);
		
		controls.append(
			$("<a/>")
				.nolink()
				.text("More info")
				.addClass("open-window-button")
				.click(objx.bind(this.openWindow_click, this)),
			$("<a/>")
				.nolink()
				.addClass("remove-button")
				.click(objx.bind(this.close_click, this))
		);
		
		var clearer = $("<div/>").addClass("clearer");
		
		this.infoPaneEl.empty().show().append(details,controls,clearer);
		this.onOpened();
		
		// generate star
		this.starButton = new IOStarButton( star, data );
		
	},
	
	streetview: function(data) {
		IOStreetViewerInstance.showStreetView(data);
	},
	
	share: function(data) {
		IOShareModal.showModal(new IOExperienceSharingInfo(data));
	},
	
	close_click: function(){
		this.infoPaneEl.hide();
		this.onClosed();
	},
	
	openWindow_click: function(){
		
		this.onDetailsRequest();
		
	}
	
});

objx.provides("IOExperienceMapInfoHandler");
objx.requires("IOMapInfoHandler", "IOOfferMapInfoHandler")
	.requires("IOShareModal", "IOOfferMapInfoHandler")
	.requires("IOOfferSharingInfo", "IOOfferMapInfoHandler");

var IOOfferMapInfoHandler = objx.Class(IOMapInfoHandler, {
	
	hide: function() {
		if (this.infoPaneEl) {
			this.infoPaneEl.hide();
		}
	},
	
	showPopup: function(map, data, options) {

		for (var option in options){
			this[option] = options[option];
		}
		
		if (!this.infoPaneEl){
			this.infoPaneEl = $(".info-pane");
		}
		
		this.data = data;
		
		var image = $("<div/>").addClass("image");
		var details = $("<div/>").addClass("details");
		var controls = $("<div/>").addClass("controls");
		var star = $("<div/>").addClass("star");
		var extra = $("<div>").addClass("extra-details");
		
		var imgSrc = data.imageURL ? data.imageURL : null;
		var expires = data.expires ? "Expires: "+IODateTime.toNiceDate(IODateTime.fromMilliseconds(data.expires)) : null;
		
		var img = 
			$("<img/>")
				.attr("src", imgSrc)
				.attr("width", "90");

		if (data.title) {
				img.attr("alt", data.title);
		}
				
		image.append(img);
		
		if (expires) {
			extra.append(
				$("<p/>")
					.html(expires)
					.addClass("expires")
			);
		}
		
		extra.append(
			$("<p/>")
				.append(
					$("<a/>")
						.nolink()
						.text("Collect")
						.addClass("apply highlight")
						.click(objx.bind(this.apply_click, this)),
					$("<a/>")
						.addClass("share")
						.text("Share")
						.nolink()
						.click(objx.bind(this.share, this, data))
				)
		);
		
		this.addPlanDropDown = null;
		if ( null !== this.addPlanDropDown && null !== this.addPlanDropDown.addToPlansSelectEl) {
			this.addPlanDropDown.data = this.data;
			extra.append(this.addPlanDropDown.addToPlansSelectEl);
		}
		
		details.append(
			$("<h4/>").addClass("title").text(data.name),
			star,
			$("<h5/>").text("at " + data.title),
			$("<p/>").addClass("description").text(data.text),
			extra);
		controls.append(
			$("<a/>")
				.nolink()
				.addClass("open-window-button")
				.text("More info")
				.click(objx.bind(this.openWindow_click, this)),
			$("<a/>")
				.nolink()
				.addClass("remove-button")
				.click(objx.bind(this.close_click, this))
		);
		
		var clearer = $("<div/>").addClass("clearer");
		
		this.infoPaneEl.empty().show().append(image,details,controls,clearer);
		
		this.onOpened();
		
		this.starButton = new IOStarButton( star, data );
		
	},
	
	openVoucher: function(){
		IOOfferViewer.modalIFrame(this.data.voucherURL, this.data.title, this.data.name);
	},
	
	share: function(data) {
		IOShareModal.showModal(new IOOfferSharingInfo(data));
	},
	
	close_click: function(){
		this.infoPaneEl.hide();
		this.onClosed();
	},
	
	openWindow_click: function(){
		this.openVoucher();
	},
	
	apply_click: function(){
		this.openVoucher();
	}
		
});

objx.provides("IOOfferMapInfoHandler");
objx.requires("IOControl", "IOSearchBox");
objx.requires("IOFullPostcodeGeocoderService", "IOSearchBox");

var IOSearchBox = objx.Class(IOControl, {

	// handlers
	onSearch: objx.event, // ( keywords, locaion )
	onAutoComplete: objx.event, // ( keypress )
	onReset: objx.event, // ( reset )
	onSuggestionSelected: objx.event, // ( suggestion )

	// trap on-blur
	divClick : false,
	
	// counters
	currentItem : 0, // ( selection )
	currentLimit : 0, // ( selection limit )
	currentItems : null, // ( suggestions )
	
	// keyboard codes
	enterKey : 13,
	arrowUp : 38,
	arrowDown : 40,
	
	created: function(el, discover) {
				
		this.discover = discover;
		this.searchGeocoder = new IOFullPostcodeGeocoderService();
		this.searchGeocoder.onCertainOption(objx.bind(this.geocoder_response, this));
	
		// create the search elements
		this.searchEl = $("<input type='text' id='search-box' class='input' />").clearingInput({text:"e.g. pizza"});
		var searchEl = this.searchEl;
		this.locationEl = $("<input type='text' id='location-box' class='input' />").clearingInput({text:"e.g. London, Ipswich, SE16 etc."});
		var locationEl = this.locationEl;
	
		this.goButtonEl = $("<input type='submit' value='' class='submit' />");
		var goButtonEl = this.goButtonEl;
		this.locationsEl = $("<div class='locations'></div>");
		var locationsEl = this.locationsEl;

		// bind events
		goButtonEl.click(objx.bind(this.goButtonEl_click, this));
		
		// add the elements
		el.append($("<span class='find-text'>What:</span>"), searchEl, $("<span>Where:</span>"), locationEl, goButtonEl);
		$("body").append(locationsEl);

		searchEl.keydown(objx.bind(this.searchEl_keydown, this));
		
		locationEl.keyup(objx.bind(this.searchEl_autocomplete, this));
		locationEl.keydown(objx.bind(this.locationEl_keydown, this));
		
		locationEl.blur(objx.bind(function(event) {
			if ( this.divClick ) { return( this.divClick = false ); }
			if ((event.keyCode != this.arrowUp) && (event.keyCode != this.arrowDown)) {
				this.locationsEl.hide();
			}
		}, this));		
		
		var offset = locationEl.offset();
		this.locationsEl.css({left: offset.left - 9, top: offset.top + 33});
		
	},
	
	geocoder_response: function(location){

		if (this.locationOnlySearch()) { 
			// move the map
			this.discover.mapBox.setLocation(location, 15);
		}
		
		if (!this.locationOnlySearch()) { 
			this.onSearch(this.searchVal, this.locationVal, location);
		}		
		
	},
	
	search: function(keywords, location){
		
		this.searchVal = searchVal = this.searchEl.hasClass("blur") ? "" : this.searchEl.val();
		this.locationVal = locationVal = this.locationEl.hasClass("blur") ? "" : this.locationEl.val();
		
		if (locationVal !== "" && searchVal !== "") {
			this.discover.clearMap();
			this.discover.categoryPanel.resetCategories();
			this.discover.categoryPanel.updateCategoryCounts();
			this.searchGeocoder.find(locationVal);
		} else if (locationVal === "" && searchVal !== "") {
			this.onSearch(this.searchVal, "", null);
		} else if (searchVal === "" && locationVal !== "") {
			this.discover.clearMap();
			this.searchGeocoder.find(locationVal);			
		}
		
	},
	
	locationOnlySearch: function() {
		return this.searchVal === "" && this.locationVal !== "";
	},
	
	goButtonEl_click: function() {

		this.hideOptions();
		this.search();

	},
	
	searchEl_autocomplete: function(event) {

		var value = this.locationEl.val();

		if ( (event.keyCode != this.enterKey) && (event.keyCode != this.arrowUp) && (event.keyCode != this.arrowDown) ) {
			if (value.length >= 3) {
				this.onAutoComplete(value);
			}
			else {
				this.locationsEl.hide();
			}
		}
	},
	
	searchEl_keydown: function(event) {
		
		if (event.keyCode == this.enterKey) {
			this.goButtonEl_click();
		}
		
	},
	
	locationEl_keydown: function(event) {
		
		if (this.locationsEl.css("display") == "block") {
						
			switch(event.keyCode) {				
				case this.arrowUp:
					if (this.currentItem > 0) {
						this.currentItems.eq(this.currentItem).removeClass("item-selected");
						this.currentItem--;
						this.currentItems.eq(this.currentItem).addClass("item-selected");
					}
					break;

				case this.arrowDown: 
					if (this.currentItem < this.currentLimit) { 
						this.currentItems.eq(this.currentItem).removeClass("item-selected");
						this.currentItem++;
						this.currentItems.eq(this.currentItem).addClass("item-selected");
					}
					break;
				
				case this.enterKey:
					if ( this.currentItems.eq(this.currentItem).hasClass("item-selected") ) {
						this.suggestion_click(this.currentItems.get(this.currentItem).innerHTML);
					}
					else {
						this.goButtonEl_click();
					}
					break;
			}
		}
		else if (event.keyCode == this.enterKey) {
			this.goButtonEl_click();
		}
		
	},
	
	suggest: function(suggestions) {

		var _this = this;
		// FIXME where is this.searchBox defined?
		var _elem = this.searchBox;
		var list = $("<ul/>");

		objx(suggestions.Placemark).each(objx.bind(function(item, i) {
			list.append(
				$("<li/>")
					.text(item.address)
					.click(objx.bind(function(item) {
						_elem.suggestion_click(item);
					}, _this, item.address))
					.mousedown(objx.bind(function() {
						_elem.divClick = true;
					}, _this))
				);
		}, this));
		
		_elem.locationsEl.empty().show().append(list);

		_elem.currentItem = -1;
		_elem.currentItems = _elem.locationsEl.find("li");
		_elem.currentLimit = _elem.currentItems.length-1;
					
	},
	
	suggestion_click: function( suggestion ) {

		this.locationEl.val(suggestion);
		this.locationsEl.hide();
		
		//this.onSuggestionSelected(suggestion);
		
	},
	
	hideOptions: function() {
		
		this.locationsEl.hide();
		this.searchEl.focus().select();		

	},
	
	reset: function() {
		
		this.searchEl.val("");
		this.locationEl.val("");
	
	}

});

objx.provides("IOSearchBox");
objx.requires("IOControl", "IOCategoryPanel");

var IOCategoryPanel = objx.Class(IOControl, {
	
	onCategoriesUpdated: objx.event,
	onCategoryClick: objx.event,
	onClearCategories: objx.event,
	
	cookieName: "selectedCategoryPanelOptions",
	
	categoryPanel: null,
	categories: null,

	created: function(categoryPanelElement, categories) {
		if ( categoryPanelElement && categories ) {
			this.categories = jQuery.extend(true, {}, categories);
			this.categoryPanel = categoryPanelElement;
			this.createCategoryPanelElements();
			this.onCategoryClick( objx.bind(this.saveCategorySelections, this, this.categories) );
			this.onCategoryClick( this.updateCategoryCounts );
		}
	},
	
	selectSubCategory: function(cat) {
		cat.selected = true;
		cat.linkEl.addClass("selected");
	},
	
	deselectSubCategory: function(cat) {
		cat.selected = false;
		cat.linkEl.removeClass("selected");
	},
	
	createCategoryPanelElements: function() {
		var previouslySelectedCats = this.loadCategorySelections();
		var eventsUL = $("<ul/>").addClass("events");
		this.categoryPanel.append(eventsUL);
		objx(this.categories).each( objx.bind( function(category) {
			
			category.listEl = $("<li/>").addClass("discover-header " + category.name.toLowerCase());
			eventsUL.append(category.listEl);
			category.linkEl = $("<a/>")
			   							.nolink()
			   							.click( objx.bind(this.category_click, this, category ) )
			   							.addClass("title")
										.append(
											$("<span/>").addClass("cat-icon"),
											$("<span/>").css("float","right").text(category.name)
										);
			category.spanEl = $("<span/>").addClass("counter");
			category.subCategoryUL = $("<ul/>").hide();
			category.listEl.append(category.linkEl,
						   			category.spanEl,
						   			category.subCategoryUL);
			
			objx(category.categories).each( objx.bind( function(subCategory) {
				
				subCategory.linkEl = $("<a/>").text(subCategory.name)
											   	  .attr("id", subCategory.id)
											   	  .nolink()
											   	  .click( objx.bind(this.subCategory_click, this, subCategory, category ) );
				if ("All" === subCategory.id) {
					subCategory.linkEl.addClass("all-types");
				}
 
				subCategory.listEl = $("<li/>").addClass("discover-sub-header")
						  					  	   .append(subCategory.linkEl);
				
				if ( undefined !== previouslySelectedCats ) {
					objx(previouslySelectedCats).each( objx.bind( function(selectCat) {
						if ( category.name + "/" + subCategory.id === selectCat ) {
							this.selectSubCategory(subCategory);
						}
					}, this));
				}
				
				category.subCategoryUL.append(subCategory.listEl);
				
			}, this));
			
		}, this));
		
		// FIXME - Requires class and CSS styling.
		this.resetEl = $("<a/>")
			.nolink()
			.addClass("reset-link")
			.text("Reset Map")
			.click(objx.bind(this.resetEl_click, this))
			.appendTo(this.element);
	},
	
	loadCategories: function(){
		this.onCategoriesUpdated(this.categories);
	},
	
	saveCategorySelections: function(cats) {
		// FIXME - save the selections in cookie for now. Should extract logic in future.
		var selectedCats = [];
		objx(cats).each( objx.bind( function(category) {
			objx(category.categories).each( objx.bind( function(subCategory) {
				if ( subCategory.selected ) {
					selectedCats.push(category.name + "/" + subCategory.id);
				}
			}, this));
		}, this));
		var json = { "categories" : selectedCats };		
		$.JSONCookie(this.cookieName, json, {path: "/"});
	},
	
	loadCategorySelections: function() {
		// FIXME - load the selections from cookie for now. Should extract logic in future.
		return $.JSONCookie(this.cookieName).categories;
	},
	
	updateCategoryCounts: function() {
		objx(this.categories).each( objx.bind( function(category) {
			var selectionCount = 0;
			
			objx(category.categories).each( objx.bind( function(subCategory) {
				if ( subCategory.selected ) {
					selectionCount++;
				}
			}, this));
			
			if ( selectionCount > 0 ) {
				category.spanEl.text(selectionCount);
			}
			else {
				category.spanEl.text("");
			}
			
		}, this));
	},
	
	getSelectedCategories: function() {
		var selectedCategories = [];
		objx(this.categories).each( objx.bind( function(category) {
			objx(category.categories).each( objx.bind( function(category, subCategory) {
				if ( subCategory.selected ) {
					subCategory.parent = category.name;
					selectedCategories.push(subCategory);
				}
			}, this, category));
		}, this));
		return selectedCategories;
	},
	
	resetCategories: function(){
		objx(this.categories).each(objx.bind( function(cat){
			objx(cat.categories).each(objx.bind( function(subcat){
				this.deselectSubCategory(subcat);
			}, this));
		}, this));
	},
	
	category_click: function(cat) {
		var currentOpenCategory = this.element.find(".open").text();
		this.element.find(".open").removeClass("open").siblings("ul").slideUp("fast");
		if ( cat.name !== currentOpenCategory ) {
			cat.linkEl.addClass("open").parents("li").find("ul").slideDown("fast");
		}
	},
	
	subCategory_click: function(cat, parent) {
		if ( false === cat.selected ) {
			if ("All" === cat.id) {
			    // deselect all sibling categories
				objx(parent.categories).each( objx.bind( function(siblingCategory) {
					if ( "All" != siblingCategory.id ) {
						this.deselectSubCategory(siblingCategory);
					}
				}, this));
			} else {
				// deselect All types
				objx(parent.categories).each( objx.bind( function(siblingCategory) {
					if ( "All" === siblingCategory.id ) {
						this.deselectSubCategory(siblingCategory);
					}
				}, this));
			}
			this.selectSubCategory(cat);
		}
		else {
			this.deselectSubCategory(cat);
		}
		
		this.onCategoryClick(this.categories);
		
		this.loadCategories();
	},
	
	resetEl_click: function(){
		this.resetCategories();
		this.updateCategoryCounts();
		this.loadCategories();
		this.saveCategorySelections(this.categories);
		this.onClearCategories();
	}

});

objx.provides("IOCategoryPanel");
objx.requires("IOControl", "IOFavouriteTab")
	.requires("IODraggable", "IOFavouriteTab");

var IOFavouriteTab = objx.Class(IOControl, {
	
	onItemClicked: objx.event,
	
	favouritesEl : null,
	
	created: function(el) {
	
		this.newFavouriteLink = $("h3.your-favourites");
		this.favouritesEl = el;
		
		IOStar_callback = objx.bind(this.star_callback, this);
		
		var droppableFavourites = new IODroppable(this.newFavouriteLink);
		droppableFavourites.onItemDropped(objx.bind(this.itemDropped, this));
		
		this.show();
	},
	
	show: function() {
	  
		//this.favouritesEl.empty();

		if (IOEgg.stars.length > 0) {
			objx(IOEgg.stars).each(objx.bind(function(item, i) {
				this.addFavourite(item, this.favouritesEl);
			}, this));
		}	

	},
	
	star_callback: function(elemId, starred, data) {

		if (starred) { 
			// add favourite
			this.addFavourite(data, this.favouritesEl);
		}
		else { 
			// remove favourite
			this.favouritesEl.find("li:."+elemId).remove();
			
		}
	},

	addFavourite: function(item, elem) {

		this.favouritesEl.parent().find("p").hide();

		// create star button element
		var star = $("<div/>");

		// generate star
		this.starButton = new IOStarButton( star, item );
		
		var starListItem = $("<li/>")
			.addClass(this.starButton.starId + " star-item")
			.append(
				star,
				$("<a/>")
					.addClass("star-name")
					.text(item.title)
					.nolink()
					.click(objx.bind(this.onItemClicked, this, item))
			);
		
		IODraggable(starListItem, { helper: "clone" }, item);
		
		// create star button element
		elem.append(starListItem);

	},
	
	itemDropped: function(item) {
		var starEl = $(".list-view ." + createStarId(item));
		if (!starEl.hasClass("starred")) {
			starEl.click();
		}
	}
		
});

objx.provides("IOFavouriteTab");
objx.requires("IOControl", "IOPlanTab")
	.requires("IOShareModal", "IOPlanTab")
	.requires("IOPlanSharingInfo", "IOPlanTab");

var IOPlanTab = objx.Class(IOControl, {
	
	onPlanSelected: objx.event,
	onNewplanClicked: objx.event,
	
	plansEl : null,
	
	created: function(el) {
	
		this.plansEl = el.find(".plan-items");	
		this.newEl = el.find(".new-plan");	

		this.newplanEl = $("<a class='plan-button'><img src ='/img/buttons/new-plan.gif' width='115' height='24'/></a>").nolink();
		var newplanEl = this.newplanEl;
		
		newplanEl.click(objx.bind(this.newplanEl_click, this));
		this.newEl.append(newplanEl);
	
		IOPlan.onAllLoaded(objx.bind(this.loadPlans_callback, this));
		IOPlan.onCreated(objx.bind(this.showNewPlan_onCreated, this));
		IOPlan.onDeleted(objx.bind(this.planDeleted, this));
		IOPlan.onSaved(objx.bind(this.planSaved, this));
		
		this.makeNewPlanLink = $("h3.your-week-ahead");
		var droppableMakePlan = new IODroppable( this.makeNewPlanLink );
		droppableMakePlan.onItemDropped(objx.bind(this.itemDroppedOnMakeNewPlan, this));
		this.makeNewPlanLink.click(objx.bind(this.makeNewPlanLink_click, this));
		
		this.loadPlans();
	},
	
	loadPlans: function() {
		IOPlan.all();
	},
	
	loadPlans_callback: function( response ) {
		if (response) {
			this.updateView(response);
		}
	},
	
	updateView: function(plans) {
		
		this.plans = plans;
		this.plansEl.empty();
		
		objx(plans).each(objx.bind(function(planData, i) {
			this.addPlan(planData);
		}, this));
		
	},
	
	addPlan: function(planData) {
		
		var planEl = $("<li/>")
						.addClass(this.getPlanTabId( planData.id ))
						.appendTo(this.plansEl);
				
		var planManager = new IOPlanDataManager(planData);

		var planOptions = 
				$("<div/>")
				.addClass("plan-actions")
				.append(
					$("<a/>")
						.text("view")
						.attr("href", IORedirect.getPlanViewerLink(planData.id, planManager.getPrivateKey() )),
					$("<a/>")
						.text("edit")
						.nolink()
						.click(objx.bind(this.editPlanLinkEl_click, this, planData.id)),
					$("<a/>")
						.text("share")
						.nolink()
						.click(objx.bind(this.sharePlanLinkEl_click, this, planData)),
					$("<a/>")
						.text("delete")
						.nolink()
						.click(objx.bind(this.planDelete_click, this, planData.id))
				);
		
		var openCloseLink = $("<div/>").addClass("plan-open-close")
										.append(
												$("<a/>")
												.text( "+" )
												.nolink()
												.click(objx.bind(this.togglePlan, this, planEl))
										);
		
		var planTitle = $("<div/>").addClass("plan-title-line")
							.append(
									$("<a/>")
										.addClass("plan-title")
										.text(IOPlanHelper.getPlanTitle(planData))
										.nolink()
										.click(objx.bind(this.plan_click, this, planData))
								);
		
		
		var planLegs = $("<div/>").addClass("plan-legs").addClass("clearer").hide();
		
		objx(planData.legs).each(objx.bind(function(leg, index){
			this.createPlanLeg(leg, planLegs);
		}, this));
		
		planEl.append(planTitle);
		
		var droppablePlan = new IODroppable( planEl );

		droppablePlan.onItemDropped(objx.bind(this.itemDropped, this, planManager, planEl));
		
		return planEl;
	},
	
	plan_click: function(plan) {
		this.showPlan(plan);
	},
	
	showPlan: function(plan) {	  
    // show plan in editable panel
		this.onPlanSelected(plan);
	},
		
	createPlanLeg: function (leg, legsEl) { 
		
		var experienceIcon = $("<img/>")
								.addClass("event-marker")
								.attr({ "src" : IOPin.getPin(leg.type || 0).img });
		
		var legTitleEl = $("<p/>")
			.html(leg.title || "<em>Untitled</em>");
		
		var legInfoEl = $("<div/>").addClass("plan-tab-leg")
									.addClass("clearer")
									.append(
										experienceIcon, 
										legTitleEl);
		
		legsEl.append( legInfoEl );
	},
	
	planSaved: function(plan) {
	
		this.loadPlans(); 
		return; 
		
	},
	
	updatePlanTitle: function(planElement, planData) {
		planElement.find(".plan-title").text( IOPlanHelper.getPlanTitle(planData) );
	},
	
	updatePlanLegs: function(planElement, leg) {
		this.createPlanLeg(leg, planElement.find(".plan-legs"));
	},
	
	planDelete_click: function(planId) {
		if (confirm("Are you sure you want to delete this plan?")) {
			this.planElementToBeDeleted = $("." + this.getPlanTabId(planId));
			IOPlan.del(planId);
		}
	},
	
	planDeleted: function(planId) {
		
    // remove plan element from ui
		this.plansEl.find(".plan-tab-"+planId).remove();
		
	},
	
	itemDropped: function(planManager, planReceivingDrop, item) {
		
		var leg = planManager.createLegFromItem(item);
		var newPlanData = planManager.data().obj();

		this.saveUpdatedPlan( newPlanData );
		this.showPlan(newPlanData);
		
	},
	
	itemDroppedOnMakeNewPlan: function(experience) {
		this.draggedExperience = experience;
		this.makeNewPlanLink_click();
	},
	
	saveUpdatedPlan: function(plan) {
		IOOnce("save-plan", 
			objx.bind(function(plan){
				IOPlan.save( plan.id, plan );
			}, 
			this, 
			plan)
		);
	},
	
	makeNewPlanLink_click: function() {
		IOPlan.create();
	},
	
	showNewPlan_onCreated: function( planData ) {
		
		planEl = this.addPlan( planData );
		
		if(this.draggedExperience) {
			this.plans.push(planData);
			this.itemDropped(new IOPlanDataManager(planData), planEl, this.draggedExperience);
			this.draggedExperience = null;
		}
		
	},
	
	getPlanTabId: function(planId) {
		return "plan-tab-" + planId;
	},

	sharePlanLinkEl_click: function(planData){
		IOShareModal.showModal( new IOPlanSharingInfo(planData) );
	},
	
	editPlanLinkEl_click: function(planId){
		IOModal.iFrame(IORedirect.getPlanEditorLink(planId), 980);
	},
	
	newplanEl_click: function() {
		
		this.onNewplanClicked();
		
	}
	
});

objx.provides("IOPlanTab");
objx.requires("IOPage", "IODiscoverBox")
	.requires("IOExperienceMapInfoHandler", "IODiscoverBox")
	.requires("IOOfferMapInfoHandler", "IODiscoverBox")
	.requires("IOPlanService", "IODiscoverBox")
	.requires("IOExperienceService", "IODiscoverBox")
	.requires("IOGeocoderService", "IODiscoverBox")
	.requires("IOFavouriteTab", "IODiscoverBox")
	.requires("IOPlanTab", "IODiscoverBox")
	.requires("IOSearchBox", "IODiscoverBox")
	.requires("IODroppable", "IODiscoverBox")
	.requires("IOOnce", "IODiscoverBox")
	.requires("IOAddPlanDropDown", "IODiscoverBox");

var IODiscoverBox = objx.Class(IOControl, {

	experiences: [],
	searchExperiences: [],
	
	findElements: function(){
		
		this.searchEl = this.element.find("#search");
		this.mapEl = this.element.find(".actual-map");
		this.specialsEl = this.element.find(".special-items");
		this.offersEl = this.element.find(".offers");
		this.plansEl = this.element.find(".options-plans");
		this.favoritesEl = this.element.find(".options-favorites .starred-items");
		this.eventsEl = this.element.find("#events");
		
		this.planEditorEl = this.element.find(".middle-bar .editor");
		this.planEditorPanelEl = this.element.find("#plan-editor-panel");
		this.inContentPlanEditorPanel = this.element.find("#plan-editor-panel");
		this.inContentDetailsViewPanel = this.element.find("#details-view-panel");
		this.inContentMapPanel = this.element.find("#map-panel");
		this.inContentPanels = this.element.find("#in-content-panels");
		
		this.addPlanDropDown = new IOAddPlanDropDown();
		this.addPlanDropDown.onPlanUpdated(objx.bind(this.addPlanDropDown_onPlanUpdated, this));
		this.detailsHandler = new IOExperienceMapInfoHandler(this.addPlanDropDown);
		this.offerHandler   = new IOOfferMapInfoHandler(this.addPlanDropDown);
		
		this.detailsHandler.onOpened(objx.bind(this.popup_onOpened, this));
		this.detailsHandler.onClosed(objx.bind(this.popup_onClosed, this));
		this.detailsHandler.onDetailsRequest(objx.bind(this.detailsHandler_detailsRequest, this));
		this.offerHandler.onOpened(objx.bind(this.popup_onOpened, this));
		this.offerHandler.onClosed(objx.bind(this.popup_onClosed, this));
		
	},

	created: function(element) {

		this.findElements();
		
		this.inContentPanels.tabs();
		
		// create the plan editor
		this.planEditor = new IOPlanEditor(this.planEditorEl);
		this.planEditor.onPlanChanged(objx.bind(this.planEditor_onPlanChanged, this));
		this.planEditor.onPlanDeleted(objx.bind(this.planEditor_onPlanDeleted, this));
		
		var droppablePlanEditor = new IODroppable(this.planEditor.element, { accept: ".star, .star-item" });
		droppablePlanEditor.onItemDropped(objx.bind(this.planEditor_dropped, this));
		
		this.categoryPanel = new IOCategoryPanel(this.eventsEl, categories);
		
		if (this.mapEl) {

			this.mapBox = new IOMap(this.mapEl);
			
			this.mapBox.onMapLoaded(objx.bind(this.mapBox_onMapLoaded, this));
			this.mapBox.toggleView(objx.bind(this.toggleListView, this));
			
			this.experienceService = new IOExperienceService();
			this.experienceService.onExperienceSearchByKeyword(objx.bind(this.onSearchByKeyword_response, this));
			this.experienceService.onExperienceSearchByCategory(objx.bind(this.onSearchByCategory_response, this));
			this.experienceService.onEventsAtSearch(objx.bind(this.onSearch_response, this));
			this.experienceService.onExperienceDetails(objx.bind(this.experienceService_experienceDetails, this));

			this.offerService = new IOOfferService();
			this.offerService.onOfferSearch(objx.bind(this.offer_callback, this));
			this.offerService.onOffersAtSearch(objx.bind(this.offersAt_response, this));

			this.mapBox.createHiddenDraggableMarker();
			this.mapBox.restorePositionAndZoom(IOEgg.location, 12);

			// 53.800651,-4.064941

			this.searchBox = new IOSearchBox(this.searchEl, this);
			this.searchBox.onAutoComplete(objx.bind(this.onSearch_autocomplete, this));
			this.searchBox.onSuggestionSelected(objx.bind(this.onSuggestion_click, this));
			this.searchBox.onSearch(objx.bind(this.onSearch_click, this));
			this.categoryPanel.onClearCategories(objx.bind(this.searchBox.reset, this.searchBox));


			this.searchGeocoder = new IOGoogleGeocoderService();
			this.searchGeocoder.onOptions(objx.bind(this.searchBox.suggest, this));
			
			this.favouriteTab = new IOFavouriteTab(this.favoritesEl);
			this.favouriteTab.onItemClicked(objx.bind(this.favouriteTabItem_click, this));
			
			this.planTab = new IOPlanTab(this.plansEl);
			this.planTab.onPlanSelected(objx.bind(this.planTab_onPlanSelected, this));
			this.planTab.onNewplanClicked(objx.bind(this.onNewPlan_click, this));
			
			this.element.find(".close-content-button").click(objx.bind(this.closeContentButton_click, this));

			this.mapBox.onLocationChangeEnd(objx.bind(this.mapLocation_change, this));
			this.mapBox.onLocationChangeEnd(objx.bind(this.restoreResults, this));
			this.mapBox.onMapMoved(objx.bind(this.map_dragged, this));

			this.categoryPanel.onCategoriesUpdated(objx.bind(this.categories_updated, this));
			this.categoryPanel.onCategoryClick(objx.bind(this.categories_click, this));
			this.categoryPanel.onClearCategories(objx.bind(this.resetButtonClicked, this));
			
			// FIXME - should we use events to trigger the two functions below?
			this.categoryPanel.loadCategories();
			this.categoryPanel.updateCategoryCounts();
			
			if (typeof IOHub != "undefined"){
				
				IOHub.onExperienceSelected(objx.bind(this.hub_experienceSelected, this));
				IOHub.onOfferSelected(objx.bind(this.hub_offerSelected, this));
				
			}
			
			//this.restoreResults();
			
		}
		
	},
	
	categories_click: function() {
	
		if (this.currentContentPanel != this.inContentMapPanel) {
			this.displayMapPanel();
		}
		
		this.mapBox.resetOverlays();
		
	},
	
	resetButtonClicked: function() {
		
		this.searchBox.searchVal = null;
		this.clearMap();
		
	},
	
	toggleListView: function() {

		// hide plan editor panel if being displayed
		if (this.planEditorPanelEl.is(":visible")) {
			this.displayMapPanel();
		}

		if (this.mapBox.listViewEl.data('displayed')) {
			this.mapBox.listViewEl.fadeOut("fast", objx.bind(function() {
				if ($(".map-toggle")) { $(".map-toggle").text("List View"); }
			}, this));
			this.mapBox.dropDownMenu.enabled = true;
			this.mapBox.map.enableDoubleClickZoom();
			this.mapBox.map.enableScrollWheelZoom();
		}
		else {
			this.mapBox.listViewEl.fadeIn("fast", objx.bind(function() {
				if ($(".map-toggle")) { $(".map-toggle").text("Map View"); }
			}, this));
			this.mapBox.dropDownMenu.enabled = false;
			this.mapBox.map.disableDoubleClickZoom();
			this.mapBox.map.disableScrollWheelZoom();
		}

		this.mapBox.listViewEl.data('displayed', !this.mapBox.listViewEl.data('displayed'));
	},

	showInContentPage: function(element) {
		this.selectAContentPane(element);
	},
	
	selectAContentPane: function(element) {
		this.currentContentPanel = element;
		this.inContentPanels.tabs('select', element.attr('id'));
	},

	displayMapPanel: function() {
		this.selectAContentPane(this.inContentMapPanel);
		this.mapBox.normal();
	},
	
	restoreResults: function() {
		// invoked on onLocationChangeEnd
		/*
		// perform keyword search after page-load only if we previously set some keywords
		var keywords = $.cookie('search-keywords');
		var location = this.mapBox.getCenter();

		if (null !== keywords && 0 < keywords.length) {
			this.mapBox.resetOverlays();
			this.experienceService.experienceSearchByKeyword(location, this.getMapRadius(), keywords);
		}
				
		// highlight search input if not a location selection
		if (!this.searchBox.searchEl.hasClass("blur") && this.searchBox.searchEl.length > 0) { this.searchBox.searchEl.focus().select(); }
		*/
		
		this.mapBox.resetOverlays();
		
	},
	
	categorySearch: function() {
		var loc = this.mapBox.getCenter();
		var selectedCategories = this.categoryPanel.getSelectedCategories();
		var cats = [];
		var offers = false;
		
		objx(selectedCategories).each( objx.bind( function(category) {
			if ( category.name === "Offers" ) {
				offers = true;
			} else {
				cats.push(category);
			}
		}, this ));
		
		if (0 !== cats.length) {
			this.experienceService.experienceSearchByCategory(loc, this.getMapRadius(), cats);
		}

		if (offers){
			this.offerService.offerSearch(loc, this.getMapRadius());
		}
	
		if (0 === cats.length && !offers) {
			this.plotAllItems();
		}
		
		
	},
	
	searchByKeyword: function(keywords) {
		
		if (null !== keywords) {
			
			var loc = this.mapBox.getCenter();
			this.experienceService.experienceSearchByKeyword(loc, this.getMapRadius(), keywords);
		
		}
		
	},
	
	searchByKeywordAndLocation: function(keywords, locationString, location){
		
		if (keywords && null !== keywords) {
			
			this.experienceService.experienceSearchByKeywordAndLocation(keywords, locationString, location);
			
		}
		
	},
	
	plotItems: function(items, handler){
		
		handler = handler || this.detailsHandler;
		
		if (items){
		
			this.mapBox.plotItems(items, { 
				popupHandler: handler
			});
			
		}
		
	},
	
	getMapRadius: function(){
		return this.mapBox.getRadiusFromBounds();
	},
	
	categories_updated: function(){
		
		this.mapBox.resetOverlays();
		this.experiences = [];
		this.offers = [];
		this.categorySearch();
		
	},
	
	onSearch_autocomplete: function(response) {

		// researched, and no clear way of restricting area to UK only at present
		this.searchGeocoder.find(response + ", UK");

	},
	
	onSearch_click: function(keywords, locationString, location) {
		this.mapBox.resetOverlays();
		this.searchExperiences = [];
		if (location === null) {
			var loc = this.mapBox.map.getCenter();
			location = {lat: loc.lat(), lng: loc.lng()};
		}
		
		if (locationString && locationString !== ""){
			if (this.mapBox.myLocationMarker){
				this.mapBox.myLocationMarker.setLatLng(new GLatLng(location.lat, location.lng));
			} else {
				this.mapBox.createMyLocationMarker();
				this.mapBox.myLocationMarker.setLatLng(new GLatLng(location.lat, location.lng));
			}
		}
		
		this.searchByKeywordAndLocation(keywords, locationString, location);
	
		if (this.currentContentPanel != this.inContentMapPanel) {
			this.displayMapPanel();
		}

	},
	
	onNewPlan_click: function(){
	
		IOPlan.create();
		
	},
				
	clearMap: function(response) {
		this.experiences = [];
		this.searchExperiences = [];
		this.offers = [];
		this.mapBox.resetOverlays();
	},
	
	onSearchByCategory_response: function(response) {
		this.processResponse(response, this.experiences, false);
	},	
	
	onSearchByKeyword_response: function(response) {
		this.processResponse(response, this.searchExperiences, true);
	},
	
	offer_callback: function(response) {
		this.processResponse(response, this.offers, false);
	},
	
	processResponse: function(response, items, resizeMap) {

		if (response) {
			if (response.length > 0) {
	
				var newSearch = this.experiences.length === 0 && this.searchExperiences.length === 0 && this.offers.length === 0;
	
				objx(response).each(objx.bind(function(item, i) {
					items.push(item);
				}, this));
	
				this.plotAllItems();
				
				if (newSearch && resizeMap) {
					this.updateMapView(this.mapBox.items, this.mapBox.myLocationMarker);
				}
				
			}		
			else { // no items, updateMap with position of myLocationMarker.
				if (this.searchBox.locationEl.val().length > 0) {
					this.updateMapViewLocationMarker(this.mapBox.myLocationMarker);
				}
			}
		}
		
	},
	
	plotAllItems: function() {
		this.plotItems(this.experiences);
		this.plotItems(this.searchExperiences);
		this.plotItems(this.offers, this.offerHandler);
	},
	
	planEditor_onPlanChanged: function(plan) {

		// called when the plan editor has made a change to a plan
		this.planTab.saveUpdatedPlan(plan);

	},
	
	planEditor_onPlanDeleted: function(id) {
	
		// hide the plan editor
		this.displayMapPanel();
		
	},
	
	planTab_onPlanSelected: function(plan) {
		
		// deactivate any elements editable in plan-editor before switching to another plan
		var planEditablesEl = $("#plan-editor-panel.editable");
		
		if (planEditablesEl.length > 0) {
			planEditablesEl.editable('disable');
		}
	
		this.planEditor.setPlan(plan);
		this.showInContentPage(this.inContentPlanEditorPanel);
		
	},
	
	onSuggestion_click: function(response) {

		this.mapBox.gClientGeocoder.getLocations(
			response, 
			objx.bind(this.changeLocation, this)
		);

	},
	
	changeLocation: function(response) {
		
		var location = {};
		location.lat = response.Placemark[0].Point.coordinates[1];
		location.lng = response.Placemark[0].Point.coordinates[0];

		this.mapBox.onLocationChange(location, IOMapConstants.locationSearchZoom);
		
	},
	
	generateExperienceDetails: function(response){
		
		var data = response.data[0];
		
		var imageHTML = "<div class='content-item middle'>";
		
		if (data.details.imageURLs){
			objx(data.details.imageURLs).each(objx.bind(function(o){
				imageHTML += "<img src='"+ o +"' />";
				}, this));
		}
		
		imageHTML += "</div>";
		
		return '<ul class="content-item top">' +
			
	        '<li class="content-left detail-title">'+
	          '<ul>'+
	            '<li id="title">'+
	              '<h3>' + (data.title || "Untitled") + '</h3>' +
	           ' </li>'+
	          '</ul>'+
	        '</li>'+

	      '</ul>'+

	   '   <ul class="content-item middle">'+

	        '<li class="content-right detail-info">'+
	          '<ul>'      +
				'<li id="address">'+
	              '<div class="icons address"></div>'+
	             ' <p class="address-details">'+
	                (data.details.address || "") + ' ' +
	                (data.details.postcode || "") +
	              '</p>'+
	            '</li>'+

	            '<li id="phone">'+
	                (data.details.phoneNumber || "") +
	            '</li>'+
	            '<li id="other-events-at">' +
	            '</li>'+
	          '</ul>'+
	        '</li>'+

	      '</ul>'+

	      '<ul class="content-item middle">'+
			'<li id="description">'+
                '<p>'+
					(data.details.description || "") +
				'</p>'+
            '</li>'+
	      '</ul>'+
	
		  imageHTML +

	      '<div class="clearer">'+

		'</div>';
			
	},
	
	isEvent: function(experience) {
		return experience.details.eventVenueId;
	},
	
	generateTicketingInformation: function(html, ticketLinks, firstIsEvent){
	
		html = $("<div/>").css({position:"absolute",width:"100%"}).html(html);
		
		ticketLinksEl = $("<ul/>").addClass("content-item").appendTo($("<div/>"));
		
		this.ticketingItems = [];
		var el = null;
		
		objx(ticketLinks).each(objx.bind(function(o){
			if (this.isEvent(o)) {
				el = $("<li/>").addClass("event-item").appendTo(ticketLinksEl);
				this.ticketingItems.push(new IOTicketingItem(el, o, this.experienceService, firstIsEvent));
			}
		}, this));
	
		ticketLinksEl.insertAfter(html.find(".middle").eq(0));
		
		return html;
		
	},
	
	mapBox_onMapLoaded: function(){
		this.mapBox.createDropDownMenu();
	},
	
	closeContentButton_click: function(){
		this.displayMapPanel();
	},
	
	planEditor_dropped: function(data){
		this.planEditor.createLegFromStar(data);
	},
	
	detailsHandler_detailsRequest: function(){

		this.experienceService.getExperienceDetails(this.detailsHandler.data);
		
	},
	
	experienceService_experienceDetails: function(response){
		
		var closeButton = $("<a/>").addClass("remove-button").click(objx.bind(this.inContentPaneCloseButton_click, this));
		
		var firstExperience = response.data[0];

		var html = this.generateExperienceDetails(response);
		
		if (response.data.length > 0){
			var firstIsEvent = this.isEvent(firstExperience);
			if (!firstIsEvent) {
				objx(response.data).removeAt(0);
			}
			html = this.generateTicketingInformation(html, response.data, firstIsEvent);	
		}
		
		this.inContentDetailsViewPanel.empty().append($(html).append(closeButton));
		
		var otherEventsEl = $("#other-events-at");
		if (this.isEvent(firstExperience) && 0 < this.inContentDetailsViewPanel.find(".event-item").length && firstExperience.details.eventVenueTitle) {
			var otherEventsLink = $("<a/>")
						 .text("... more at " + firstExperience.details.eventVenueTitle)
						 .addClass("other-events-at")
						 .click(objx.bind(this.otherEventsAt_click, this, firstExperience));
			otherEventsEl.append(otherEventsLink);
			otherEventsEl.show();
		} else {
			otherEventsEl.hide();
		}
		
		this.showInContentPage(this.inContentDetailsViewPanel);
		
		this.offerService.offersAt(firstExperience);
		
	},
	
	offersAt_response: function(data) {
		
		var offerList = $("<ul>").addClass("content-item middle");

		objx(data).each(objx.bind(function(offer) {
			// FIXME use jQuery to populate elements rather than HTML
			offerList.append(
				"<li class=\"border offer content-left detail-title\">" + 
					"<ul><li><h3 style=\"line-height: 23px;\">" + offer.name + "</h3></li></ul>" + 
					"<img src=" + offer.imageURL + " title=\"" + offer.title + "\" style=\"max-height: 180px;\"/>" + 
					"<p class=\"name\">" + (offer.text ? offer.text : "") + "</p>" +
					"<a href=\"javascript:void(0);\" title=\"" + offer.name + "\" class=\"apply\" " +  
						"onclick=\"IOOfferViewer.modalIFrame('" + offer.voucherURL + "','" + offer.title + "','" + offer.name + "');\">Collect</a>" + 
				"</li>");
		}, this));

		this.inContentDetailsViewPanel.children(":first").append(offerList);
		
	},
	
	otherEventsAt_click: function(eventExperience) {
		this.experienceService.getExperienceDetails({experienceId: eventExperience.details.eventVenueId});
	},
	
	inContentPaneCloseButton_click: function(){
		this.displayMapPanel();
	},
	
	favouriteTabItem_click: function(star){
		if (star.type === IOItemType.experience){
			this.experienceService.getExperienceDetails(star);
		} else if (star.type === IOItemType.offer){
			IOModal.iFrame(star.details.voucherURL);
		}
	},
	
	showOfferDetailsOnInContentPane: function(offer){
		
		var closeButton = $("<a/>").addClass("remove-button").click(objx.bind(this.inContentPaneCloseButton_click, this));
		
		var offerTitle = $("<span/>").append(
								$("<span/>").addClass("offer-name").text(offer.name), 
								$("<span/>").addClass("offer-title").text("at " + offer.title),
								$("<span/>").text(offer.expires ? "expires on " + IODateTime.msToNiceDateTime(offer.expires) : "No expiry date"));
		
		var offerText = $("<p/>").append( offer.text );
		
		var collectLink = $("<a/>")
									.text("Collect")
									.nolink()
									.click( objx.bind( IOModal.iFrame, IOModal, offer.voucherURL, 650, 550) );

		var offerImage = $("<img/>").addClass("offer-image").attr( 'src', offer.imageURL );
			
		this.inContentDetailsViewPanel.empty().append(offerTitle, offerText, collectLink, offerImage, closeButton);
		
		this.showInContentPage(this.inContentDetailsViewPanel);
		
	},
	
	updateMapView: function(items, myLocationMarker){
		
		if (!items && !myLocationMarker) { return; }
		
		var bounds = new GLatLngBounds();
		
		items = objx(items);
		
		if (items.size() > 0) {
		
			items.each(function(i){
				if (i) {
					bounds.extend(new GLatLng(i.location.lat, i.location.lng));
				}
			});
		
		}

		if (myLocationMarker) {
			bounds.extend(myLocationMarker.getLatLng());
		}
		
		this.mapBox.temporarilyDisableOnMapMoved();
		var zoom = Math.min(16, this.mapBox.map.getBoundsZoomLevel(bounds));
		this.mapBox.map.setCenter(bounds.getCenter(), zoom);
	},
	
	updateMapViewLocationMarker: function(myLocationMarker){
		this.mapBox.temporarilyDisableOnMapMoved();
		var zoom = 16;
		this.mapBox.map.setCenter(myLocationMarker.getLatLng(), zoom);
	},
	
	mapLocation_change: function(){
		this.categoryPanel.loadCategories();
	},
	
	map_dragged: function(){
		this.searchBox.locationEl.val("");
		this.categorySearch();
		var keywords = this.searchBox.searchVal;
		var loc = this.mapBox.getCenter();
		this.searchByKeywordAndLocation(keywords, null, loc);
	},

	popup_onOpened: function() {
		//this.mapBox.smaller();
	},

	popup_onClosed: function() {
		this.mapBox.normal();
	},
	
	hub_experienceSelected: function(sender, id){
		this.experienceService.getExperienceDetailsById(id);
		$.scrollTo({top:100,left:0},200);
	},
	
	hub_offerSelected: function(sender, id){ // Listing id from bview voucher is a different listing id for the same listing.
		this.hub_experienceSelected(sender, id);
	},
	
	addPlanDropDown_onPlanUpdated: function(plan) {
		this.planTab_onPlanSelected(plan);
	}
		
});

objx.provides("IODiscoverBox");
// dependencies
objx.requires("objx.Class", "IODropDownMenu")
	.requires("IOControl", "IODropDownMenu");

IODropDownMenu = objx.Class(IOControl, {
	
	ioMap: null,
	menuElement: null,
	clickedPixel: null,
	enabled: true,
	
	init: function(el) {
	
		if ( el !== undefined )
			{ this.element = el; }
		
		this.created();
	
	},
	
	created: function() {
		
		this.ioMap = this.element;
		
		var menuContents = $("<a/>").text("Set my location to here")
									.bind("click", objx.bind(this.triggerLocationChanged,this));
		this.menuElement = $("<div></div>").addClass("map-right-click-menu")
                        .html(menuContents)
                        .appendTo(this.ioMap.map.getContainer());
				
	},

	offset: function(top, left) {
		
		this.menuElement.css("top", top);
		this.menuElement.css("left", left);
		
	},
	
	hide: function() {
		
		this.menuElement.css("visibility", "hidden");
		
	},
	
	show: function(point) {

		if ( this.enabled  ) {
			this.clickedPixel = point;
			this.menuElement.css("visibility", "visible");		
		}
	
	},
	
	triggerLocationChanged: function() {
		
		var position = this.ioMap.map.fromContainerPixelToLatLng(this.clickedPixel);
		this.ioMap.onLocationChange({ lat: position.lat(), lng: position.lng() });
		this.hide();
		
	}
	
});

objx.provides("IODropDownMenu");
objx.requires("objx.Class", "IODirections")
	.requires("IOControl", "IODirections");

var IODirections = objx.Class(IOControl, {

	getPolyline: true,
	getSteps: true,
	travelMode: G_TRAVEL_MODE_DRIVING,
	onDirectionsLoaded: objx.event, // ( Array data ) triggered when all directions have been loaded
	
	getDirections: function(locations, opts){
		var options = opts || {};
		
		for (var property in options){
			this[property] = options[property];
		}
		
		var dir = new GDirections();
	
		locations = objx(locations).collect(function(item) { return item.lat+","+item.lng; }).obj();
		
		GEvent.addListener(dir, "load", objx.bind(this.directions_load, this, dir));
		GEvent.addListener(dir, "error", function(){ $.log(dir.getStatus().code); });
	
		dir.loadFromWaypoints(locations, {
			getPolyline:this.getPolyline,
			getSteps:this.getSteps,
			travelMode:options.travelMode ? options.travelMode : this.travelMode
		});
	},
	
	getDirectionsHtml: function(dir){
	
		var list = $("<ol/>");
		var listItem = null;
		var route = null;
		
		for (var i=0, il=dir.getNumRoutes(); i<il; i++){
			
			route = dir.getRoute(i);
			listItem = $("<li/>");
			
			for (var j=0, jl=route.getNumSteps(); j<jl; j++){
			
				listItem.append($("<p/>").html(route.getStep(j).getDescriptionHtml())).appendTo(list);
				
			}
			
			list.append(listItem);
			
		}
		
		return $(list.html());
		
	},
	
	directions_load: function(dir){
		this.onDirectionsLoaded(dir);
	}

});

objx.provides("IODirections");
objx.requires("objx.Class", "IODirections2");

/*
 *  IODirections2.loadDirections([{
 *    lat: 123, lng: 456,
 *    travelToNext: IOWalk | IODrive
 *  }])
 */

var IODirections2 = objx.Class({
	
	onUpdate: objx.event, // (index, directions, total-results-to-date, directions-manager)
	onComplete: objx.event, // (results, directions-manager)
	
	locations: null,
	results: null,
	
	busy: false,
	current: 0,
	total: 0,
	
	bounds: null,
	
	defaultTravelMode: G_TRAVEL_MODE_DRIVING,
	
	init: function() {
		
		// create a directions service
		this.directionsService = new GDirections(null, $("<div/>")[0]);
		var directionsService = this.directionsService;
		
		// add event listeners
		GEvent.addListener(directionsService, "load", objx.bind(this.directionsService_load, this));
		GEvent.addListener(directionsService, "error", objx.bind(this.directionsService_error, this));
		
	},
	
	loadDirections: function(locations) {

		// save the locations
		this.locations = objx(locations);

		// create a new array to hold the results
		this.results = [];
		
		// count the number of requests
		this.total = objx(locations).size() - 1;
		this.current = 0;
		
		// start the process
		this.loadNextDirection();
		
	},
	
	loadNextDirection: function() {
		
		if (this.current > this.total) {
			return;
			//throw "No more directions need to be loaded.  loadNextDirection() called too many times."
		}
		
		// get this direction
		var location = this.locations.obj()[this.current];
		
		// and the next (and increase the counter)
		var nextLocation = this.locations.obj()[++this.current];

		// convert the location objects into lat,lng string format
		var locationStrings = objx([location, nextLocation]).collect(function(l){ if (!l) { return; } return l.lat+","+l.lng; }).obj();
		
		this.directionsService.loadFromWaypoints(
			locationStrings,
			{
				getPolyline: true,
				getSteps: true,
				travelMode: location.travelToNext || this.defaultTravelMode
			}
		);

	},
	
	directionsService_load: function(d) {
		
		// save the results
		this.results.push(d);

		// and throw the update event
		this.onUpdate(this.current - 1, true, d, this.results, this);
		
		this.directions_continue();
		
	},
	
	directionsService_error: function() {
		
		var error = { error: true, status: this.directionsService.getStatus() };
		
		// save the error
		this.results.push(error);
		
		this.onUpdate(this.current - 1, false, error, this.results, this);
		
		this.directions_continue();
		
	},
	
	directions_continue: function() {
		
		// and move onto the next one
		if (this.current < this.total) {
			
			this.loadNextDirection();
			
		} else {
			
			// finished
			this.onComplete(this.results, this);
			
		}
		
	}
	
});

objx.provides("IODirections2");
// http://dspwiki.iogloballtd.com/index.php/IOMap

objx.requires("objx.Class", "IOMap")
	.requires("IOControl", "IOMap")
	.requires("IODropDownMenu", "IOMap")
	.requires("IODraggable", "IOMap");
	
var IOMapConstants = {
		defaultZoom: 17,
		locationSearchZoom: 15
};

var IOMap = objx.Class(IOControl, {

	onMapLoaded: objx.event,
	onMapDragged: objx.event,
	onMapZoomed: objx.event,
	onMapMoved: objx.event,
	on_map_moved: objx.event,
	onDirectionsLoaded: objx.event,
	onAllDirectionsLoaded: objx.event,
	onLocationChange: objx.event,
	onLocationChangeEnd: objx.event,
	onDragEnd: objx.event,

	toggleView: objx.event,
	
	locale: "en_US",
	travelMode: G_TRAVEL_MODE_DRIVING,
	
	gClientGeocoder: null,

	listViewActive: false,
	
	myLocationMarker: null,

	positionRestored: false,
	map_moved_disabled: false,
	
	created: function() {
		
		this.items = [];
		
		this.map = new GMap2(this.element.get(0));
		var map = this.map;
		
		map.addControl(new GSmallMapControl());
		map.addControl(new GMapTypeControl());
		map.addControl(new GScaleControl());
				
		map.enableContinuousZoom();
		map.enableDoubleClickZoom();
		map.disableScrollWheelZoom();
		map.disablePinchToZoom();
		
		this.resetAttributes();
	
		this.markers = [];
				
		this.gClientGeocoder = new GClientGeocoder();		
		this.gClientGeocoder.setBaseCountryCode("UK");
		
		GEvent.addListener(map, "load", objx.bind(this.onMapLoaded, this));
		GEvent.addListener(map, "dragend", objx.bind(this.onMapDragged, this));
		GEvent.addListener(map, "zoomend", objx.bind(this.onMapZoomed, this));
		GEvent.addListener(map, "moveend", objx.bind(this.on_map_moved, this));

		this.onLocationChange(objx.bind(this.setLocation, this));
    
		this.onMapZoomed(objx.bind(this.cookiePositionAndZoom, this));
		this.onMapZoomed(objx.bind(this.map_zoomed, this));
		this.onMapDragged(objx.bind(this.cookiePositionAndZoom, this));
		this.on_map_moved(objx.bind(this.map_moved, this));
		
		this.element.show();
		
	},
	
	map_zoomed: function() {
		this.temporarilyDisableOnMapMoved();
	},
	
	map_moved: function() {
		if (this.map_moved_disabled) {
			this.map_moved_disabled = false;
		}
		else {
			this.onMapMoved();
		}
	},
	
	temporarilyDisableOnMapMoved: function() {
		this.map_moved_disabled = true;
	},
	
	// make the map a bit smaller
	smaller: function() {
		this.element.addClass("smaller-map");
		this.resetAttributes();
	},
	normal: function() {
		this.element.removeClass("smaller-map");
		this.resetAttributes();
	},
	
	resetAttributes: function(){
		this.map.checkResize();
		//this.removeHybrid();
		//this.removeSatellite();
		this.removeTerrain();		
	},
	
	removeHybrid: function(){
		this.map.removeMapType(G_HYBRID_MAP);
	},
	
	removeSatellite: function(){
		this.map.removeMapType(G_SATELLITE_MAP);
	},
	
	removeTerrain: function(){
		this.map.removeMapType(G_PHYSICAL_MAP);
	},
	
	createDropDownMenu: function() {
		
		// FIXME - Right click does not work on MacFF => https://iome.acunote.com/projects/9015/tasks/292
		this.dropDownMenu = new IODropDownMenu(this);
		GEvent.addListener(this.map, "singlerightclick", objx.bind(function(point,src) {
			if (point) {
				var x = point.x;
				var y = point.y;
				if (x > this.map.getSize().width - 80) { x = this.map.getSize().width - 80; }
				if (y > this.map.getSize().height - 30) { y = this.map.getSize().height - 30; }
				var pos = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(x,y));
				this.dropDownMenu.offset(pos.offset.height, pos.offset.width);
				this.dropDownMenu.show(point);
			}
		},this));
		
		GEvent.addListener(this.map, "click", objx.bind(function() {
			this.dropDownMenu.hide();
		},this));
		
	},
	
	createMyLocationMarker: function() {
		
		// FIXME - does not work in some FF browsers.
		var gLatLng = new GLatLng( IOEgg.location.lat, IOEgg.location.lng );
		this.myLocationMarker = new GMarker(
			gLatLng, 
			{
				draggable: true,
				title: 'You are Here', 
				icon: this.createIcon(0, "/img/icons/person-icon.png", 43, 48),
				bouncy: true
			}
		);
		
		this.map.addOverlay(this.myLocationMarker);
		
		// FIXME - demo hack - persist location in cookie/server not egg.
		GEvent.addListener(this.myLocationMarker, "dragend", 
			objx.bind(this.locationMarker_dragend, this));
		
	},
	
	locationMarker_dragend: function() {
		var position = this.myLocationMarker.getLatLng();
		this.onLocationChange(
			{ lat: position.lat(), lng: position.lng() }
		);
	},
	
	createHiddenDraggableMarker: function() {
		this.element.parent().append( $("<div/>").addClass("dragablecopy") );
		
		this.draggableMarker = $(".dragablecopy");
		
		// Make draggableMarker element draggable
		IODraggable(
					this.draggableMarker,
					{
						revertDuration: 0,
						stop: function(event, ui) {
							ui.helper.css("visibility", "hidden");
						},

						start: function(event, ui) {
							ui.helper.css("visibility", "visible");
						}
					}
				);
	},
		
	addListView: function() {

		// add list-view element (hidden by-default)
		this.listViewEl = $("<div/>")
			.addClass("list-view")
			.prependTo(this.element)
			.append(
				$("<ul/>")
			);
		
		this.listViewEl.data('displayed', false);
		this.listViewActive = true;

	},

	setCenter: function(location, zoom) {
		
		var position = new GLatLng(location.lat, location.lng);

		this.map.setCenter(position);

		// must set zoom after setting center point
		if (zoom !== undefined) {
			this.map.setZoom(zoom);
		}

		if (this.myLocationMarker){
			this.myLocationMarker.setLatLng(position);
		}
		
	},
	
	setLocation: function(location, zoom) {
		
		this.setCenter(location, zoom);
		
		// FIXME - bug - maintain map zoom level.
		IOEgg.location.lat = location.lat;
		IOEgg.location.lng = location.lng;
		this.cookiePositionAndZoom();
		
		// refresh any searches
		this.onLocationChangeEnd();
	},
	
	round: function(num) {
		return Math.round(num*10000)/10000;
	},
	
	getCenter: function() {
		
		var point = this.map.getCenter();
		
		if (point) {
		
			return {
				lat: this.round(point.y),
				lng: this.round(point.x)
			};
		
		}
				
	},
	
	plotItem: function(item, options) {
		
		// check to make sure something isn't already plotted
		// at this location
		var found = false;
		objx(this.items).each(function(i){
			found = found || (i.location.lat == item.location.lat && i.location.lng == item.location.lng);
		});
		
		if (!found) {
			
			this.items.push(item);
		
			this.plotMarker(item, options);
		
			if (options.popupHandler && this.starrable(item)) {
				this.plotListItem(item);
			}
			
		}

	},
	
	starrable: function(item) {
		return item.experienceId || item.voucherId; 
	},
		
	plotMarker: function(item, options) {
		
		if (item.location){
			if (!item.location.lat || !item.location.lng){
				return;
			}
		} else {
			return;
		}
		
		var isDraggableMarker = this.draggableMarker && this.starrable(item);
		var location = new GLatLng(item.location.lat, item.location.lng);

		var theType = item.type;
		
		if (typeof theType == "undefined") {
			theType = 6;
		}

		var marker = this.createMarker(location, {
			icon: this.createIcon(item.index, options.image ? 
				// The number 6 assumes that, if the item isn't an experience with a defined type, it's an offer
				options.image : IOPin.getPin(theType, item.index).img),
			title: item.title,
			draggable: isDraggableMarker || (options.draggable === true)
		});
		
		if (options.popupHandler) {
			GEvent.addListener(marker, "click", objx.bind(function() { options.popupHandler.showPopup(this.map, item); }, this) );
		}
		
		if (isDraggableMarker) {
			GEvent.addListener(marker, "dragstart", objx.bind( this.markerDragStarted, this, item, marker, options.popupHandler) );
		}
		
		if (isDraggableMarker || (options.draggable === true)){
			GEvent.addListener(marker, "dragend", objx.bind(this.marker_dragEnd, this, item, marker));
		}
		
		this.map.addOverlay(marker);

	},
	
	markerDragStarted: function( item, marker, popupHandler, latlng ) {
		this.map.removeOverlay(marker);
		this.plotMarker(item, {icon: marker.getIcon(), popupHandler: popupHandler});
		
		var position = this.map.fromLatLngToContainerPixel(latlng);
		this.draggableMarker.css("background-image", "url(" + marker.getIcon().image + ")" );
		this.draggableMarker.css("left", (position.x - this.draggableMarker.width() ));
		this.draggableMarker.css("top", (position.y - this.draggableMarker.height() ));
		this.draggableMarker.data("data", item);
		
		this.draggableMarker.trigger(
				{
					type: "mousedown",
					dragTarget: this.draggableMarker,
					which: 1,
					pageX: (position.x - this.draggableMarker.width() / 2 ),
					pageY: (position.y - this.draggableMarker.height() / 2 )
				}
			);
	},

	clearListItems: function() {

		if (this.listViewActive) { 
			this.listViewEl.find("ul").empty();
		}

	},

	plotListItem: function(item) {

		if (this.listViewActive) {
			// create star button element
			var star = $("<div/>");

			// generate star
			this.starButton = new IOStarButton( star, item );

			var options = { "src" : IOPin.getPin(item.type || 6, item.index).img };

      // only show "drag me to favourites" if favourites panel exists in dom
      if ($(".options-favorites").length > 0) {
        options.title = options.alt = "Drag me to Favourites";
      }
			
			var draggableImage = $("<img/>")
				.addClass("list-marker")
				.attr(options);
			
			// Make draggableImage element draggable
		  IODraggable(
			  draggableImage,
				{ helper: 'clone' },
				item);
			
			var titleEl = $("<a/>")
								.text(item.title)
								.nolink()
								.addClass("list-text");
			
			if (item.experienceId)
				{ titleEl.click(objx.bind(IORedirect.toDetails, this, item.experienceId, item.title)); }
			
			this.listViewEl.find("ul").append(
				$("<li/>")
					.append(
						star,
						draggableImage,
						titleEl)
			);
		}
		
	},

	plotItems: function(items, options, bnds) {
		var bounds = bnds || new GLatLngBounds();
		var _options = options;

		objx(items).each(objx.bind(function(item, i){

			_options.draggable = false;
			
			item.index = i;
			
			if (item.draggable){
				if (item.draggable === true){
					_options.draggable = true;
				}
			}
			
			this.plotItem(item, _options);
			// calculate zoom level to include the new items.
			this.extendBounds(item.location, bounds);
			
		}, this));
		
	},
	
	extendBounds: function (location, bounds) {
		if(bounds && location) {
			if (location.lat && location.lng){
				bounds.extend(new GLatLng(location.lat, location.lng));
				// Add a diagonally symmetrical point around centre to the bound in order to retain centre of the map.
				bounds.extend(this.getSymmetricalPoint(location, this.getCenter()));
			}
		}
	},
	
	updateZoomLevel: function (bounds, offset) {
		
		offset = offset || 0;
		
		// Only zoom out, do not zoom in
		if(bounds && !bounds.isEmpty() && this.map.getZoom() > this.map.getBoundsZoomLevel(bounds)) {
			
			// Setting centre is not needed as the symmetrical points are used now.
			this.map.setZoom(this.map.getBoundsZoomLevel(bounds) + offset);
			
		}
		
	},

	resetOverlays: function() {

		this.map.clearOverlays();
		
		this.items = [];

		// Make sure that the list-view is synchronised with map-view (clearListItems() shouldn't be called anywhere else) 
		this.clearListItems();
		
		if(this.myLocationMarker)
			{ this.createMyLocationMarker(); }

	},
	
	getSymmetricalPoint: function(location, center) {
		var symLat = -location.lat + 2 * center.lat;
		var symLng = -location.lng + 2 * center.lng;
		
		if(symLat > 180)
			{symLat = 180;}
		if(symLat < -180)
			{symLat = -180;}
		if(symLng > 90)
			{symLng = 90;}
		if(symLng < -90)
			{symLng = -90;}
		
		return new GLatLng( symLat, symLng );
	},
	
	getRadiusFromBounds: function(){
		var bounds = this.map.getBounds();
		var sw = bounds.getSouthWest();
		var ne = bounds.getNorthEast();
		var se = new GLatLng(sw.lat(), ne.lng());
		var latDistance = ne.distanceFrom(se);
		var lngDistance = sw.distanceFrom(se);
		var radius = Math.round(Math.min(latDistance, lngDistance) / 2);
		return radius;
	},

	createMarker: function(location, options) {
	
		// create the marker
		return new GMarker(location, options);
		
	},
	
	createIcon: function(index, image, width, height) {
		
		var icon = new GIcon(G_DEFAULT_ICON);
		
		width = width || 25;
		height = height || 28;
		
		var size = new GSize(width, height);
		var shadowSize = new GSize(width * 1.6, height);
				
		if (arguments.length === 0){
			return null;
		} else {
			icon.image = image;
		}
		
		// set the size
		icon.iconSize = size;
		icon.shadowSize = shadowSize;
		icon.shadow = "/img/icons/pins/shadow.png";
		icon.iconAnchor = new GPoint(size.width / 2, size.height);
		icon.imageMap = [0,0,
		                 size.width, 0,
		                 size.width, size.height,
		                 0, size.height];
		
		return icon;
		
	},
	
	
	// FIXME: The map shouldn't care about directions!
	getDirections: function(legs,options) {
		this.directions = new IODirections();
		legs = objx(legs).collect(function(item){return item.location;}).obj();
		
		this.directions.getDirections(legs, options);
		this.directions.onDirectionsLoaded(objx.bind(this.directions_load, this));
	},
	
	// FIXME: The map shouldn't care about directions!
	getDirectionsHtml: function(dir){
		return this.directions.getDirectionsHtml(dir);
	},
	
	// FIXME: The map shouldn't care about directions!
	directions_load: function(dir){
		this.onDirectionsLoaded(dir);
	},
	
	marker_dragEnd: function(item, marker){
		this.onDragEnd(item, marker);
	},
	
	cookiePositionAndZoom: function() {
		var zoom = this.map.getZoom();
		$.cookie('map-zoom' + window.location.pathname, zoom);
		var loc = this.getCenter();
		$.cookie('location-lat' + window.location.pathname, loc.lat);
		$.cookie('location-lng' + window.location.pathname, loc.lng);
	},
	
	restorePositionAndZoom: function(defaultLocation, defaultZoom, usePreciseZoom) {
		
		var location = defaultLocation;
		var zoom = defaultZoom || IOMapConstants.defaultZoom;

		if (!usePreciseZoom) {

			var lat = $.cookie('location-lat' + window.location.pathname);
			var lng = $.cookie('location-lng' + window.location.pathname);
			var zoomLevel = $.cookie('map-zoom' + window.location.pathname);

			if (null !== lat && null !== lng && null !== zoomLevel) { 
			
				location = { 'lat': lat, 'lng': lng } ;
				zoom = usePreciseZoom ? parseInt(zoomLevel, 10) : Math.min(parseInt(zoomLevel, 10), 9);
				this.positionRestored = true;
			
			}
			
			this.setLocation(location, zoom);
		
		} else {
			
			this.setLocation(location, zoom);
			
		}
		
	},

	zoomBoundsIfNotRestored: function(bounds) {
		
		if (!this.positionRestored && bounds && 'undefined' != typeof bounds.isEmpty() && !bounds.isEmpty()) {
			
			var boundsCentre = bounds.getCenter();
			var point = new GLatLng(this.round(boundsCentre.y), this.round(boundsCentre.x));
			this.map.setCenter(point, this.map.getBoundsZoomLevel(bounds));
			this.cookiePositionAndZoom();
			
		}
		
	}

});

objx.provides("IOMap");
objx.requires("IOControl", "IOStreetViewer");

var IOStreetViewer = objx.Class(IOControl, {
	
	panoWidth: "700px",
	panoHeight: "250px",
		
	createPopup: function(){
		$("<div/>").css({"font-size":"15px", "color":"#66C", "font-weight":"bold"}).addClass("place-name").appendTo(this.element);
		this.streetViewEl = $("<div/>").css({width:this.panoWidth,height:this.panoHeight}).appendTo(this.element);
		this.panoView = new GStreetviewPanorama(this.streetViewEl.get(0));
		GEvent.addListener(this.panoView, "error", this.handleError);
	},

	showStreetView: function(data){
		
		if (!this.panoView){
			this.createPopup();
		}
		
		$(".place-name").text(data.title);
		
		this.location = data.location;
		this.panoView.setLocationAndPOV(new GLatLng(this.location.lat, this.location.lng));
		
		IOModal.init(this.element, {
			width: this.panoWidth,
			controls: "OK",
			onOk: objx.bind(this.removeStreetView, this),
			okText: "OK"
		});
	},

	removeStreetView: function(){
		this.panoView.remove();
		IOModal.close();
	},
	
	handleError: function(errorCode) {
		var error = "Other Error";
		switch(errorCode){
			case GStreetviewPanorama.ErrorValues.FLASH_UNAVAILABLE:
				error = "Your browser does not have a flash player or has a very old version of it";
				break;
			case GStreetviewPanorama.ErrorValues.NO_NEARBY_PANO:
				error = "No streetview is available at this location";
				break;
			default:
				break;
		}
		
		$(".place-name").text(error);
	}

});

var IOStreetViewerInstance = new IOStreetViewer(
	$("<div/>").addClass("street-viewer").appendTo("body")
);

objx.provides("IOStreetViewer");
objx.requires("IOControl", "IOTicketingItem");

var IOTicketingItem = objx.Class(IOControl, {

	open: false, // is information already visible for this ticketing item?
	data: null,
	
	created: function(element, experience, service, firstIsEvent){
		
		this.experience = experience;
		this.experienceService = service;
		this.experienceService.onExperienceEventDetails(objx.bind(this.experienceEventDetails_success, this));
		
		var eventLinkLabel = firstIsEvent ? "Click for times" : experience.title;
		this.element.append(
			$("<a/>")
				.nolink()
				.text(eventLinkLabel)
				.click(
					objx.bind(this.experience_click, this)
				)
				.addClass("event-title")
		);
		
		this.data = experience;
		this.createTicketingInformation(experience);

	},
	
	createTicketingInformation: function(exp){
	
		this.ticketDrawerEl = $("<div/>").addClass("event-details").hide().appendTo(this.element);
		
		if (exp.details.imageURLs){
			if (exp.details.imageURLs.length > 0){
				this.ticketDrawerEl.append($("<img/>").attr("src", exp.details.imageURLs[0]));
			}
		}
		
		ticketListEl = $("<ol/>").appendTo(this.ticketDrawerEl);
		
		var tickets = objx(exp.details.ticketLinks).group(function(o){
		
			return o.when.date.day + " " + IODateTime.months[o.when.date.month-1] + ", " + o.when.date.year + " 23:59:59";
		
		}).obj();
		
		var ticketDatesCount = 0;
		
		for (var data in tickets){
			
			if (new Date(data) >= (new Date())){
				
				ticketDatesCount++;

				var dateListEl = $("<li/>").appendTo(ticketListEl);
				
				if (ticketDatesCount % 2 !== 0){
					dateListEl.css("clear","both");
				}
				
					dateListEl.append($("<h5/>").html(IODateTime.toNiceDate(new Date(data))));
			
					var timeListEl = $("<ol/>").appendTo(dateListEl);
			
					objx(tickets[data]).each(objx.bind(function(o){

						var timeEl = null;
						
						if (o.ticketURL) {
						
							timeEl = $("<a/>");
						
							timeEl.attr({
								"href" : IOEgg.session.restUrlPrefix + "/linkout/ticket?url=" + escape(o.ticketURL) + "&lat=" + IOEgg.location.lat + "&lng=" + IOEgg.location.lng,
								"target" : "_blank"
							});
							
						} else {
						
							timeEl = $("<span/>");
							
						}
						
						if (o.when.time) {
							timeEl.text( 
										IOMath.pad(o.when.time.hour, 2) +
										":" +
										IOMath.pad(o.when.time.minute, 2)
									);
						} else {
							timeEl.text("Please phone for times");
						}

						timeListEl.append(
							$("<li/>").append(timeEl)			
						);
			
					}, this));
			
			}
		
		}
		
		if (ticketDatesCount === 0){
			ticketListEl.append($("<li/>").text("No event times found.").addClass("message"));
		}
				
	},
	
	openTicketingInformation: function(){
		this.ticketDrawerEl
			.append($("<div/>").addClass("clearer"))
			.slideDown();

		this.open = true;
		this.element.addClass("open");
	},
	
	closeTicketingInformation: function(){
		var _this = this;
		this.ticketDrawerEl.slideUp(500, function(){ 
			_this.element.removeClass("open");
			_this.ticketDrawerEl.hide();
		});
		this.open = false;
	},
	
	experience_click: function(){
		
		if (this.open) {
			this.closeTicketingInformation();
		} else {
			if (this.data){
				this.openTicketingInformation(this.data);
			} else {
				this.experienceService.getExperienceEventDetailsById(this.experience.experienceId, this);
			}
		}
		
	},
	
	experienceEventDetails_success: function(response, context){
		if (context && context == this){
			this.data = response;
			this.openTicketingInformation(response);
		}
	}
	
});

objx.provides("IOTicketingItem");
objx.requires("objx.Class", "IOFacebookService");

var IOFacebookService = objx.Class({	

	onLoaded: objx.event,
	onFriends: objx.event,
	onUsers: objx.event,
	onEmail: objx.event,
	onQuery: objx.event,
	onLogout: objx.event,
	
	requiredFields: ["uid", "first_name", "last_name", "pic_square", "proxied_email"],

	init: function() {
		FB.init(IOEgg.keys.facebookConnect, this.receiverUrl());
	},

	apiKey: function() {
		return FB.ApiClient(IOEgg.keys.facebookConnect, this.receiverUrl(), null);
	},
	
	connect: function() {

		var api = this.apiKey();
		api.users_getInfo(
		  [api.get_session().uid],
		  this.requiredFields, 
		  objx.bind(this.connect_success, this, api.get_session().session_key )
		);
		
	},
	
	connect_success: function( fb_session_key, response ) {

		this.onLoaded(response, fb_session_key);
		
	},

	friends: function() {
	
	  var api = this.apiKey();
	  api.friends_get(null,
	    objx.bind(this.friends_success, this)
	  );
	  
	},
	
	friends_success: function( response ) {
	  
    this.users(response);
	
	},
	
	users: function( uids ) {
	  
	  if (uids) {
			var api = this.apiKey();
			api.users_getInfo(
			  uids,
			  this.requiredFields, 
			  objx.bind(this.users_success, this)
			);
    }
	  
	},
	
	users_success: function( response ) {
	  
	  this.onUsers(response);
	  
	},
	
	email: function ( uids, subject, body ) {
	
	  // e.g.
	  // IOFacebook.email(["100000361984000"], "test", "test")
	
	  if (uids) {
	    var api = this.apiKey();
	    api.notifications_sendEmail(
	     uids,
	     subject,
	     body,
	     "",
	     objx.bind(this.email_success, this)
	    );
	  }
	      
	},
	
	email_success: function ( response ) {
	
	  this.onEmail(response);
	
	},
	
	query: function ( fql ) {
	
	  if (fql) {
	    var api = this.apiKey();
	    api.fql_query(
	     fql,
	     objx.bind(this.query_success, this)
	    );
	  }
	  
	},
	
	query_success: function ( response ) {
	
	  this.onQuery(response);
	  
	},
	
	logout: function () {
	  
	  $.JSONCookie('facebook', {});
	  this.onLogout();
	  
	},
	
	receiverUrl: function () {
		if (window.location.protocol == 'https:') {
			return '/connect/xd_receiver_ssl';
		}
		else {
			return '/connect/xd_receiver';
		}
	}
		
});

// default instance
var IOFacebook = new IOFacebookService();

objx.provides("IOFacebookService");
objx.requires("IOControl", "IOFacebookConnect")
	.requires("IOFacebookService", "IOFacebookConnect")
	.requires("IOFacebookConnectService", "IOFacebookConnect")
	.requires("IORedirect", "IOFacebookConnect");

var IOFacebookConnect = objx.Class(IOControl, {

	created: function(el, options) {

		this.options = options;

		// link to default facebook service
		IOFacebook.onLoaded(objx.bind(this.onConnect_success, this));
		IOFacebookConnectService.onConnectSuccess(objx.bind(this.facebookConnectService_onConnectSuccess, this));

    	if ("true" == IOEgg.session.loggedIn) { this.refreshLoginElements(); }

	},
	
	createFacebookUsername: function(facebookData) {
	    return facebookData.last_name.substring(0,4) + facebookData.first_name.substring(0,4) + facebookData.uid;
	},
	
	onConnect_success: function(response, fb_session_key) {

		var facebookData = response[0];

	    // store JSON inside cookie
	    $.JSONCookie(this.options.cookieName, facebookData, {path: '/'});

		// POST to fbconnect with fb_session_key and other data from response[0]
		// FIXME deal with failure
		var fbUsername = this.createFacebookUsername(facebookData);
		connectData = { "fb_session_key" : fb_session_key,
		                "fb_uid" : facebookData.uid,  
		                "fb_name" : facebookData.first_name,
		                "fb_username" : fbUsername
		              };

		IOFacebookConnectService.connect(connectData);

	    this.refreshLoginElements();
    
	},
	
	facebookConnectService_onConnectSuccess: function() {
		window.location.reload();
	},
	
	refreshLoginElements: function() {
	  
	  // read in json cookie
	  var data = $.JSONCookie(this.options.cookieName);
	
	  // read in facebook data, if present show user name, etc.
	  if (data.first_name) {
	      var el = $("<ul/>")
			.addClass("login-details")
			.append(
				$("<li/>")
					.addClass("avatar")
					.append(
						$("<img/>")
							.attr({
								alt: data.first_name + " " + data.last_name,
								src: data.pic_square
							})							
							.addClass("avatar-square")
						),					
				$("<li/>")
					.addClass("user-name")
					.text(data.first_name + " " + data.last_name),
				$("<li/>")
					.append(
						$("<a/>").text("log out").nolink().click(objx.bind(this.logout, this))
					)
			);

			this.element.empty().append(el);
			this.titleEl = $(".header").find(".title");
	    }

		// show login area after load
		this.element.css("visibility", "visible");
	  
	},
	
	logout: function() {

		IOFacebook.logout();
		IORedirect.logout();

	}
	
});

$(function(){
	// fixme - removed from IOPage as creates un-needed dependency, placed here temporarily until better place found
	var fbConnect = new IOFacebookConnect($(".header-login"), { "cookieName" : "facebook" });
});

objx.provides("IOFacebookConnect");
objx.requires("IOPage", "IOLocationSelector");

var IOPlanViewerMap = objx.Class(IOControl, {
	
	onWalkingElClicked: objx.event,
	onDrivingElClicked: objx.event,
	
	directionsPolylines: null,
	customStartPoint: false,
	customEndPoint: false,
			
	bindEvents: function(){
		this.mapControl.onDragEnd(objx.bind(this.map_dragEnd, this));
	},
	
	created: function(el){
		
		this.mapControl = new IOMap(this.element);
		this.directionsManager = new IODirections2();
		
		this.directionsManager.onUpdate(objx.bind(this.directionsManager_onUpdate, this));
		this.directionsManager.onComplete(objx.bind(this.directionsManager_onComplete, this));
		
		this.directionsEl = $("<ol/>");
		$(".directions").append(this.directionsEl);
		
		this.bounds = new GLatLngBounds();
		
		this.bindEvents();

	},
	
	showPlan: function(legs){
		
		this.legs = legs;
		
		this.mapControl.restorePositionAndZoom(this.calculateCenter(legs), null, true);

		var handler = new IOMapInfoHandler();
		
		handler.showPopup = function(map, data) {

			var position = new GLatLng(data.location.lat, data.location.lng);

			// generate popup element
			var content = $("<div/>")
				.addClass("map-popup");

			var time = data.when.time ? 
			  $("<li/>").text(IOMath.pad(data.when.time.hour, 2) + ":" + IOMath.pad(data.when.time.minute, 2)) : null;
			
			// generate details element
			var details = $("<div>")
				.addClass("details").append(
					$("<ul>")
						.addClass("experience-details").append(
							time,
							$("<li/>")
								.append($("<h4/>").text(data.title)),
							$("<li/>")
								.append($("<p/>").text(data.description))
						)
				);
			
			// generate clear element
			var clear = $("<div/>")
				.addClass("clearer");

			// generate extra element
			var extra = $("<div>")
				.addClass("extra-details").append(
					$("<ul>").append(
							$("<li/>")
								.text(data.shortDescription),
							$("<li/>").append(
								$("<a/>")
									.text("View Details")
									.nolink()
									.click(objx.bind(IORedirect.toDetails, this, data.experienceId, data.title))
							)
					)
				);

			// create star button element
			var star = $("<div/>");

			// append elements for display
			content
				.append(
					star,
					details,
					clear,
					extra);

			// open popup
			this.openPopup(map, content.get(0), position);

		};
		
		if (legs){
			
			if (this.customStartPoint === true){
				legs.unshift({
					draggable: true,
					location: IOEgg.location,
					when: {},
					title: "Start"
				});
			}
			
			if (this.customEndPoint === true){
				legs.push({
					draggable: true,
					location: IOEgg.location,
					when: {},
					title: "Finish"
				});
			}
			
			this.mapControl.resetOverlays();
			
			this.mapControl.plotItems(legs, {
				icon: this.mapControl.createIcon(),
				popupHandler: handler
			}, 
			this.bounds);
			
			this.mapControl.updateZoomLevel(this.bounds);
			
		}
		
	},
	
	calculateCenter: function(items) {
		if (0 < items.length) {
			var maxLat = -90;
			var minLat = 90;
			var maxLng = -1000;
			var minLng = 1000;
			
			objx(items).each(objx.bind(function(item, i) {
				minLat = Math.min(minLat, item.location.lat);
				maxLat = Math.max(maxLat, item.location.lat);
				minLng = Math.min(minLng, item.location.lng);
				maxLng = Math.max(maxLng, item.location.lng);
			}, this));
			
			var latCenter = (minLat + maxLat) / 2; 
			var lngCenter = (minLng + maxLng) / 2; 
			
			return { lat: latCenter, lng: lngCenter };
		}
		else {
			return IOEgg.location;
		}
	},
	
	getDirections: function(locations){
		
		// clear the pane
		this.directionsEl.empty().text("Loading details...");
		
		// clear the polylines on the map
		if (this.directionsPolylines) {
			objx(this.directionsPolylines).each(objx.bind(function(polyline){
				this.mapControl.map.removeOverlay(polyline);
			}, this));
		}
		
		if (locations.length > 1) {
		
			// start loading directions
			this.directionsManager.loadDirections(locations);
		
		} else {
			
			// just add this single item
			this.directionsManager_onUpdate(0, true, null);
			
		}
		
	},
	
	directionsManager_onUpdate: function(index, isSuccess, directions) {
		
		// is this the first one?
		if (index === 0) {
			this.directionsEl.empty();
		}
		
		if (isSuccess && directions) {
		
			// write this update
			this.showDirections(index, directions);
			
			// save the polyline overlay
			var polyline = directions.getPolyline();
			this.directionsPolylines = this.directionsPolylines || [];
			this.directionsPolylines.push(polyline);
			this.drawPolyline(polyline);
		
		} else {
			
			var leg = this.legs[index];
			if (leg) {
				this.directionsEl.append(this.addDirectionsTitle(leg), "<ol style='clear:both'></ol>");
			}
			
		}
		this.mapControl.zoomBoundsIfNotRestored(this.bounds);
	},
	
	directionsManager_onComplete: function() {
		
		this.addDirectionsTitle(this.legs[this.legs.length-1]);
		
	},
	
	drawPolyline: function(polyline){
		var pb = polyline.getBounds();
		this.bounds.extend(pb.getNorthEast());		
		this.bounds.extend(pb.getSouthWest());		
		this.mapControl.map.addOverlay(polyline);
		
	},
	
	showDirections: function(index, dir){
		
		if (typeof index != "undefined" && dir) {
			
			var routes = dir.getNumRoutes();
			
			var route = dir.getRoute(0);
			var leg = this.legs[index];
		
			var routeItem = this.addDirectionsTitle(leg);
			
			var travelMode = this.addTravelMode(leg);

			var stepsList = $("<ol/>");
		
			// write each step
			for (var si = 0; si < route.getNumSteps(); si++) {
			
				stepsList.append("<li>" + route.getStep(si).getDescriptionHtml() + "</li>");
			
			}
			
			routeItem.append(travelMode, stepsList);
			this.directionsEl.append(routeItem);
		
		}		
	},
	
	addTravelMode: function(leg){
		
		var travelMode = 
			$("<li/>").append(
				$("<ul/>").addClass("travel-mode").append(
					$("<li>").append($("<a/>").text("Walk").click(objx.bind(this.walkingEl_click, this, leg))),
					$("<li>").append($("<a/>").text("Drive").click(objx.bind(this.drivingEl_click, this, leg)))
				)
			);
		
		
		return travelMode;
		
	},
	
	addDirectionsTitle: function(leg) {
		
		var time = "";
		
		if(leg.when){
			if (leg.when.time){
				time = IOMath.pad(leg.when.time.hour, 2) + ":" + IOMath.pad(leg.when.time.minute, 2) + " ";
			}
		}
		
		var routeItem = $("<li/>");
		
		routeItem.append(
			$("<h4>" + time + IOPlanHelper.getLegTitle(leg) + "</h4>")
		
		);
		
		this.directionsEl.append(routeItem);
		
		return routeItem;
		
	},
	
	walkingEl_click: function(leg){
		this.onWalkingElClicked(leg);
	},
	
	drivingEl_click: function(leg){
		this.onDrivingElClicked(leg);
	},
	
	map_directions_loaded: function(dir){
		
		this.drawPolyline(dir);
		this.showDirections(dir);
		
		var bounds = dir.getBounds();
		this.mapControl.map.setCenter(bounds.getCenter(), this.mapControl.map.getBoundsZoomLevel(bounds)); 
		
	},
	
	map_dragEnd: function(item, marker){
		this.legs[item.index] = item;
		
		var p = marker.getPoint();
		
		this.legs[item.index].location = {
			lat: p.lat(),
			lng: p.lng()
		};
		
		this.getAllDirections(this.legs, this.directionsListEl);
	}

});

var zoomfunc = null;

objx.provides("IOPlanViewerMap");
objx.requires("objx.Class", "IOCommentsList")
	.requires("IOControl", "IOCommentsList");

/*
 *  new IOCommentsList( ULDomElement )
 */

var fakeComments = [
    {
      message: "This was a great night!",
      messageURL: "http://twitter.com/MatRyerAtIome/status/3686957819",
      user: "MatRyerAtIome",
      userURL: "http://twitter.com/MatRyerAtIome",
      userIconURL: "http://twitter.com/account/profile_image/MatRyerAtIome?hreflang=en",
      source: "Twitter",
      created: 1251809138748
      // no resources
    },
    {
      message: "I had an awesome time! www.bit.ly/4gryRu",
      messageURL: "http://twitter.com/jagiome/status/3686209682",
      user: "jagiome",
      userURL: "http://twitter.com/jagiome",
      userIconURL: "http://twitter.com/account/profile_image/jagiome?hreflang=en",
      source: "Twitter",
      created: 1251809138748,
      resources: [{
        type: 0,
        location: "http://www.iogloballtd.com/",
        text: "IO Global Ltd Website"
        // no details
      }]
    },
    {
      message: "Can't believe you can eat on the tube! http://bit.ly/qroog",
      messageURL: "http://twitter.com/MatRyerAtIome/status/3686957818",
      user: "MatRyerAtIome",
      userURL: "http://twitter.com/MatRyerAtIome",
      userIconURL: "http://twitter.com/account/profile_image/MatRyerAtIome?hreflang=en",
      source: "Twitter",
      created: 1251809138748,
      resources: [{
        type: 2,
        location: "http://www.youtube.com/watch?v=ywLhNwSBizE",
        text: "London underground dinner party",
        details: {
          youTubeId: "ywLhNwSBizE"
        }
      }]
    }
];

var IOCommentsList = new objx.Class(IOControl, {
	
	created: function() {
		
	},
	
	showComments: function(planComments) {
		
		objx(planComments.comments).each(objx.bind(function(comment, index){
			
			this.addComment(comment, index);
			
		}, this));

	},
	
	addResource: function(messageEl, resource, index){
		if (2001 == resource.type) {
			messageEl.append(
					$("<img/>")
						.addClass("comment-resource")
						.attr("src", resource.location)
			);
		}
		if (3001 == resource.type) {
			var videoUrl = "http://www.youtube-nocookie.com/v/" + resource.details.youTubeId + "&hl=en&fs=1&rel=0";
			messageEl.append(
					$("<div/>")
						.addClass("comment-resource")
						.html("<object width=\"320\" height=\"265\"><param name=\"movie\" value=\"" + videoUrl + "\"></param><param name=\"allowFullScreen\" value=\"true\"></param><param name=\"allowscriptaccess\" value=\"always\"></param><embed src=\"" + videoUrl + "\" type=\"application/x-shockwave-flash\" allowscriptaccess=\"always\" allowfullscreen=\"true\" width=\"320\" height=\"265\"></embed></object>")
			);
		}
		

	},
	
	addComment: function(comment, index){
		var dt = new Date(comment.created);

		comment.message = this.applyFilters(comment.message);
		
		commentEl = $("<li/>")
			.addClass("comment-item");
		
		commentEl.append(
				$("<img/>")
					.addClass("comment-photo")
					.attr({
						"src" : comment.userIconURL,
						"alt" : comment.user,
						"height" : 48,
						"width" : 48
					})					
					.click(function() { window.open(comment.userURL, "_blank"); })
		);

		messageEl = $("<div/>")
			.addClass("comment-body");

		messageEl.append(
				$("<strong/>").append(
						$("<a/>")
							.addClass("comment-user")
							.attr("title", comment.user)
							.nolink()
							.click(function() { window.open(comment.userURL, "_blank"); })
							.text(comment.user)
		));

		messageEl
			.append($("<div/>")
			.addClass("entry-content")
			.html(comment.message));
		
		objx(comment.resources).each(objx.bind(function(resource, index){
			this.addResource(messageEl, resource, index);
		}, this));
		
		messageEl.append($("<div/>")
			.addClass("comment-time")
			.text(dt.toUTCString()));

		commentEl.append(messageEl);

		this.element.app