/*1.6.0.3*/
eval(function(p,a,c,k,e,r){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--)r[e(c)]=k[c]||e(c);k=[function(e){return r[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}('G 1e={88:\'1.6.0.3\',1R:{3W:!!(1D.77&&47.48.3q(\'49\')===-1),49:47.48.3q(\'49\')>-1,4a:47.48.3q(\'dd/\')>-1,78:47.48.3q(\'78\')>-1&&47.48.3q(\'a5\')===-1,a6:!!47.48.1f(/de.*df.*a7/)},3K:{79:!!1b.2P,a8:!!1b.a9,6f:!!1D.6g,7a:1b.3X(\'1N\')[\'4U\']&&1b.3X(\'1N\')[\'4U\']!==1b.3X(\'1y\')[\'4U\']},7b:\'<4V[^>]*>([\\\\S\\\\s]*?)<\\/4V>\',aa:/^\\/\\*-dg-([\\s\\S]*)\\*\\/\\s*$/,3g:q(){},K:q(x){o x}};E(1e.1R.a6)1e.3K.7a=1p;G 2f={2u:q(){G 2Q=1j,3h=$A(1q);E(M.2A(3h[0]))2Q=3h.4W();q 1M(){C.2I.3r(C,1q)}M.17(1M,2f.1c);1M.89=2Q;1M.ab=[];E(2Q){G 8a=q(){};8a.1k=2Q.1k;1M.1k=1t 8a;2Q.ab.1g(1M)}18(G i=0;i<3h.O;i++)1M.6h(3h[i]);E(!1M.1k.2I)1M.1k.2I=1e.3g;1M.1k.dh=1M;o 1M}};2f.1c={6h:q(25){G 3L=C.89&&C.89.1k;G 3h=M.4b(25);E(!M.4b({2J:1v}).O)3h.1g("2J","8b");18(G i=0,O=3h.O;i<O;i++){G 1z=3h[i],I=25[1z];E(3L&&M.2A(I)&&I.ac().3M()=="$4c"){G 1B=I;I=(q(m){o q(){o 3L[m].3r(C,1q)}})(1z).4z(1B);I.8b=1B.8b.2B(1B);I.2J=1B.2J.2B(1B)}C.1k[1z]=I}o C}};G 4X={};M.17=q(5x,25){18(G 1z 1O 25)5x[1z]=25[1z];o 5x};M.17(M,{2C:q(W){22{E(M.2D(W))o\'4A\';E(W===1j)o\'1j\';o W.2C?W.2C():24(W)}26(e){E(e ad di)o\'...\';4B e;}},3s:q(W){G 1r=3i W;4Y(1r){2g\'4A\':2g\'q\':2g\'dj\':o;2g\'dk\':o W.2J()}E(W===1j)o\'1j\';E(W.3s)o W.3s();E(M.4d(W))o;G U=[];18(G 1z 1O W){G I=M.3s(W[1z]);E(!M.2D(I))U.1g(1z.3s()+\': \'+I)}o\'{\'+U.2E(\', \')+\'}\'},4C:q(W){o $H(W).4C()},4e:q(W){o W&&W.4e?W.4e():24.5y(W)},4b:q(W){G 4b=[];18(G 1z 1O W)4b.1g(1z);o 4b},1S:q(W){G 1S=[];18(G 1z 1O W)1S.1g(W[1z]);o 1S},2F:q(W){o M.17({},W)},4d:q(W){o!!(W&&W.3t==1)},4D:q(W){o W!=1j&&3i W=="W"&&\'dl\'1O W&&\'2E\'1O W},8c:q(W){o W ad 3Y},2A:q(W){o 3i W=="q"},3j:q(W){o 3i W=="3k"},4Z:q(W){o 3i W=="3Z"},2D:q(W){o 3i W=="4A"}});M.17(dm.1k,{ac:q(){G 3u=C.2J().1f(/^[\\s\\(]*q[^(]*\\(([^\\)]*)\\)/)[1].1T(/\\s+/g,\'\').4f(\',\');o 3u.O==1&&!3u[0]?[]:3u},2B:q(){E(1q.O<2&&M.2D(1q[0]))o C;G 3l=C,1U=$A(1q),W=1U.4W();o q(){o 3l.3r(W,1U.1V($A(1q)))}},dn:q(){G 3l=C,1U=$A(1q),W=1U.4W();o q(19){o 3l.3r(W,[19||1D.19].1V(1U))}},8d:q(){E(!1q.O)o C;G 3l=C,1U=$A(1q);o q(){o 3l.3r(C,1U.1V($A(1q)))}},8e:q(){G 3l=C,1U=$A(1q),ae=1U.4W()*af;o 1D.dp(q(){o 3l.3r(3l,1U)},ae)},4E:q(){G 1U=[0.dq].1V($A(1q));o C.8e.3r(C,1U)},4z:q(1L){G 3l=C;o q(){o 1L.3r(C,[3l.2B(C)].1V($A(1q)))}},4F:q(){E(C.8f)o C.8f;G 3l=C;o C.8f=q(){o 3l.3r(1j,[C].1V($A(1q)))}}});dr.1k.3s=q(){o\'"\'+C.ds()+\'-\'+(C.dt()+1).4G(2)+\'-\'+C.du().4G(2)+\'T\'+C.dv().4G(2)+\':\'+C.dw().4G(2)+\':\'+C.dx().4G(2)+\'Z"\'};G ag={ah:q(){G 7c;18(G i=0,O=1q.O;i<O;i++){G ai=1q[i];22{7c=ai();2h}26(e){}}o 7c}};4g.1k.1f=4g.1k.2R;4g.aj=q(5z){o 24(5z).1T(/([.*+?^=!:${}()|[\\]\\/\\\\])/g,\'\\\\$1\')};G ak=2f.2u({2I:q(31,4h){C.31=31;C.4h=4h;C.7d=1p;C.6i()},6i:q(){C.41=al(C.6j.2B(C),C.4h*af)},8g:q(){C.31(C)},8h:q(){E(!C.41)o;am(C.41);C.41=1j},6j:q(){E(!C.7d){22{C.7d=1v;C.8g()}dy{C.7d=1p}}}});M.17(24,{5y:q(I){o I==1j?\'\':24(I)},an:{\'\\b\':\'\\\\b\',\'\\t\':\'\\\\t\',\'\\n\':\'\\\\n\',\'\\f\':\'\\\\f\',\'\\r\':\'\\\\r\',\'\\\\\':\'\\\\\\\\\'}});M.17(24.1k,{3m:q(28,3v){G 1s=\'\',25=C,1f;3v=1q.5A.8i(3v);1P(25.O>0){E(1f=25.1f(28)){1s+=25.3w(0,1f.1m);1s+=24.5y(3v(1f));25=25.3w(1f.1m+1f[0].O)}1i{1s+=25,25=\'\'}}o 1s},ao:q(28,3v,3x){3v=C.3m.8i(3v);3x=M.2D(3x)?1:3x;o C.3m(28,q(1f){E(--3x<0)o 1f[0];o 3v(1f)})},ap:q(28,1h){C.3m(28,1h);o 24(C)},dz:q(O,5B){O=O||30;5B=M.2D(5B)?\'...\':5B;o C.O>O?C.3w(0,O-5B.O)+5B:24(C)},4i:q(){o C.1T(/^\\s+/,\'\').1T(/\\s+$/,\'\')},8j:q(){o C.1T(/<\\/?[^>]+>/gi,\'\')},4j:q(){o C.1T(1t 4g(1e.7b,\'aq\'),\'\')},ar:q(){G at=1t 4g(1e.7b,\'aq\');G au=1t 4g(1e.7b,\'dA\');o(C.1f(at)||[]).2S(q(av){o(av.1f(au)||[\'\',\'\'])[1]})},50:q(){o C.ar().2S(q(4V){o 7e(4V)})},6k:q(){G 5C=1q.5A;5C.4k.7f=C;o 5C.1N.51},aw:q(){G 1N=1t J(\'1N\');1N.51=C.8j();o 1N.3n[0]?(1N.3n.O>1?$A(1N.3n).3y(\'\',q(2T,L){o 2T+L.4l}):1N.3n[0].4l):\'\'},7g:q(ax){G 1f=C.4i().1f(/([^?#]*)(#.*)?$/);E(!1f)o{};o 1f[1].4f(ax||\'&\').3y({},q(3z,1G){E((1G=1G.4f(\'=\'))[0]){G 1w=8k(1G.4W());G I=1G.O>1?1G.2E(\'=\'):1G[0];E(I!=4A)I=8k(I);E(1w 1O 3z){E(!M.4D(3z[1w]))3z[1w]=[3z[1w]];3z[1w].1g(I)}1i 3z[1w]=I}o 3z})},3A:q(){o C.4f(\'\')},8l:q(){o C.3w(0,C.O-1)+24.dB(C.ay(C.O-1)+1)},7h:q(3x){o 3x<1?\'\':1t 2m(3x+1).2E(C)},8m:q(){G 4H=C.4f(\'-\'),8n=4H.O;E(8n==1)o 4H[0];G 8o=C.7i(0)==\'-\'?4H[0].7i(0).2o()+4H[0].5D(1):4H[0];18(G i=1;i<8n;i++)8o+=4H[i].7i(0).2o()+4H[i].5D(1);o 8o},6l:q(){o C.7i(0).2o()+C.5D(1).2b()},dC:q(){o C.3m(/::/,\'/\').3m(/([A-Z]+)([A-Z][a-z])/,\'#{1}6m#{2}\').3m(/([a-z\\d])([A-Z])/,\'#{1}6m#{2}\').3m(/-/,\'6m\').2b()},dD:q(){o C.3m(/6m/,\'-\')},2C:q(az){G 8p=C.3m(/[\\dE-\\dF\\\\]/,q(1f){G 8q=24.an[1f[0]];o 8q?8q:\'\\\\dG\'+1f[0].ay().4G(2,16)});E(az)o\'"\'+8p.1T(/"/g,\'\\\\"\')+\'"\';o"\'"+8p.1T(/\'/g,\'\\\\\\\'\')+"\'"},3s:q(){o C.2C(1v)},8r:q(2i){o C.ao(2i||1e.aa,\'#{1}\')},aA:q(){G 5z=C;E(5z.52())o 1p;5z=C.1T(/\\\\./g,\'@\').1T(/"[^"\\\\\\n\\r]*"/g,\'\');o(/^[,:{}\\[\\]0-9.\\-+dH-u \\n\\r\\t]*$/).2R(5z)},5E:q(aB){G 3o=C.8r();22{E(!aB||3o.aA())o 7e(\'(\'+3o+\')\')}26(e){}4B 1t dI(\'dJ dK aC 3k: \'+C.2C());},1H:q(28){o C.3q(28)>-1},8s:q(28){o C.3q(28)===0},8t:q(28){G d=C.O-28.O;o d>=0&&C.8u(28)===d},5F:q(){o C==\'\'},52:q(){o/^\\s*$/.2R(C)},aD:q(W,28){o 1t 32(C,28).2P(W)}});E(1e.1R.4a||1e.1R.3W)M.17(24.1k,{6k:q(){o C.1T(/&/g,\'&aE;\').1T(/</g,\'&aF;\').1T(/>/g,\'&gt;\')},aw:q(){o C.8j().1T(/&aE;/g,\'&\').1T(/&aF;/g,\'<\').1T(/&gt;/g,\'>\')}});24.1k.3m.8i=q(3v){E(M.2A(3v))o 3v;G 5G=1t 32(3v);o q(1f){o 5G.2P(1f)}};24.1k.dL=24.1k.7g;M.17(24.1k.6k,{1N:1b.3X(\'1N\'),4k:1b.aG(\'\')});24.1k.6k.1N.5H(24.1k.6k.4k);G 32=2f.2u({2I:q(5G,28){C.5G=5G.2J();C.28=28||32.aH},2P:q(W){E(M.2A(W.8v))W=W.8v();o C.5G.3m(C.28,q(1f){E(W==1j)o\'\';G 53=1f[1]||\'\';E(53==\'\\\\\')o 1f[2];G 6n=W,6o=1f[3];G 28=/^([^.[]+|\\[((?:.*?[^\\\\])?)\\])(\\.|\\[|$)/;1f=28.aI(6o);E(1f==1j)o 53;1P(1f!=1j){G aJ=1f[1].8s(\'[\')?1f[2].3m(\'\\\\\\\\]\',\']\'):1f[1];6n=6n[aJ];E(1j==6n||\'\'==1f[3])2h;6o=6o.5D(\'[\'==1f[3]?1f[1].O:1f[0].O);1f=28.aI(6o)}o 53+24.5y(6n)})}});32.aH=/(^|.|\\r|\\n)(#\\{(.*?)\\})/;G $2h={};G 2K={1E:q(1h,1I){G 1m=0;22{C.4m(q(I){1h.2L(1I,I,1m++)})}26(e){E(e!=$2h)4B e;}o C},aK:q(3Z,1h,1I){G 1m=-3Z,8w=[],2v=C.3A();E(3Z<1)o 2v;1P((1m+=3Z)<2v.O)8w.1g(2v.3w(1m,1m+3Z));o 8w.8x(1h,1I)},8y:q(1h,1I){1h=1h||1e.K;G 1s=1v;C.1E(q(I,1m){1s=1s&&!!1h.2L(1I,I,1m);E(!1s)4B $2h;});o 1s},aL:q(1h,1I){1h=1h||1e.K;G 1s=1p;C.1E(q(I,1m){E(1s=!!1h.2L(1I,I,1m))4B $2h;});o 1s},8x:q(1h,1I){1h=1h||1e.K;G U=[];C.1E(q(I,1m){U.1g(1h.2L(1I,I,1m))});o U},7j:q(1h,1I){G 1s;C.1E(q(I,1m){E(1h.2L(1I,I,1m)){1s=I;4B $2h;}});o 1s},5I:q(1h,1I){G U=[];C.1E(q(I,1m){E(1h.2L(1I,I,1m))U.1g(I)});o U},dM:q(2i,1h,1I){1h=1h||1e.K;G U=[];E(M.3j(2i))2i=1t 4g(2i);C.1E(q(I,1m){E(2i.1f(I))U.1g(1h.2L(1I,I,1m))});o U},1H:q(W){E(M.2A(C.3q))E(C.3q(W)!=-1)o 1v;G 8z=1p;C.1E(q(I){E(I==W){8z=1v;4B $2h;}});o 8z},dN:q(3Z,6p){6p=M.2D(6p)?1j:6p;o C.aK(3Z,q(3w){1P(3w.O<3Z)3w.1g(6p);o 3w})},3y:q(2T,1h,1I){C.1E(q(I,1m){2T=1h.2L(1I,2T,I,1m)});o 2T},8A:q(1B){G 1U=$A(1q).3w(1);o C.2S(q(I){o I[1B].3r(I,1U)})},dO:q(1h,1I){1h=1h||1e.K;G 1s;C.1E(q(I,1m){I=1h.2L(1I,I,1m);E(1s==1j||I>=1s)1s=I});o 1s},dP:q(1h,1I){1h=1h||1e.K;G 1s;C.1E(q(I,1m){I=1h.2L(1I,I,1m);E(1s==1j||I<1s)1s=I});o 1s},dQ:q(1h,1I){1h=1h||1e.K;G 8B=[],8C=[];C.1E(q(I,1m){(1h.2L(1I,I,1m)?8B:8C).1g(I)});o[8B,8C]},5J:q(1z){G U=[];C.1E(q(I){U.1g(I[1z])});o U},dR:q(1h,1I){G U=[];C.1E(q(I,1m){E(!1h.2L(1I,I,1m))U.1g(I)});o U},aM:q(1h,1I){o C.2S(q(I,1m){o{I:I,6q:1h.2L(1I,I,1m)}}).dS(q(2w,5K){G a=2w.6q,b=5K.6q;o a<b?-1:a>b?1:0}).5J(\'I\')},3A:q(){o C.2S()},dT:q(){G 1h=1e.K,1U=$A(1q);E(M.2A(1U.2x()))1h=1U.dU();G aN=[C].1V(1U).2S($A);o C.2S(q(I,1m){o 1h(aN.5J(1m))})},aO:q(){o C.3A().O},2C:q(){o\'#<2K:\'+C.3A().2C()+\'>\'}};M.17(2K,{2S:2K.8x,8D:2K.7j,2G:2K.5I,2i:2K.5I,dV:2K.1H,dW:2K.3A,dX:2K.8y,dY:2K.aL});q $A(2U){E(!2U)o[];E(2U.3A)o 2U.3A();G O=2U.O||0,U=1t 2m(O);1P(O--)U[O]=2U[O];o U}E(1e.1R.4a){$A=q(2U){E(!2U)o[];E(!(3i 2U===\'q\'&&3i 2U.O===\'3Z\'&&3i 2U.54===\'q\')&&2U.3A)o 2U.3A();G O=2U.O||0,U=1t 2m(O);1P(O--)U[O]=2U[O];o U}}2m.aP=$A;M.17(2m.1k,2K);E(!2m.1k.8E)2m.1k.8E=2m.1k.4n;M.17(2m.1k,{4m:q(1h){18(G i=0,O=C.O;i<O;i++)1h(C[i])},aQ:q(){C.O=0;o C},3M:q(){o C[0]},2x:q(){o C[C.O-1]},dZ:q(){o C.2G(q(I){o I!=1j})},aR:q(){o C.3y([],q(2v,I){o 2v.1V(M.4D(I)?I.aR():[I])})},6r:q(){G 1S=$A(1q);o C.2G(q(I){o!1S.1H(I)})},4n:q(aS){o(aS!==1p?C:C.3A()).8E()},e0:q(){o C.O>1?C:C[0]},aT:q(aU){o C.3y([],q(2v,I,1m){E(0==1m||(aU?2v.2x()!=I:!2v.1H(I)))2v.1g(I);o 2v})},e1:q(2v){o C.aT().5I(q(54){o 2v.7j(q(I){o 54===I})})},2F:q(){o[].1V(C)},aO:q(){o C.O},2C:q(){o\'[\'+C.2S(M.2C).2E(\', \')+\']\'},3s:q(){G U=[];C.1E(q(W){G I=M.3s(W);E(!M.2D(I))U.1g(I)});o\'[\'+U.2E(\', \')+\']\'}});E(M.2A(2m.1k.aV))2m.1k.4m=2m.1k.aV;E(!2m.1k.3q)2m.1k.3q=q(54,i){i||(i=0);G O=C.O;E(i<0)i=O+i;18(;i<O;i++)E(C[i]===54)o i;o-1};E(!2m.1k.8u)2m.1k.8u=q(54,i){i=e2(i)?C.O:(i<0?C.O+i:i)+1;G n=C.3w(0,i).4n().3q(54);o(n<0)?n:i-n-1};2m.1k.3A=2m.1k.2F;q $w(3k){E(!M.3j(3k))o[];3k=3k.4i();o 3k?3k.4f(/\\s+/):[]}E(1e.1R.49){2m.1k.1V=q(){G 2v=[];18(G i=0,O=C.O;i<O;i++)2v.1g(C[i]);18(G i=0,O=1q.O;i<O;i++){E(M.4D(1q[i])){18(G j=0,aW=1q[i].O;j<aW;j++)2v.1g(1q[i][j])}1i{2v.1g(1q[i])}}o 2v}}M.17(55.1k,{e3:q(){o C.4G(2,16)},8l:q(){o C+1},7h:q(1h,1I){$R(0,C,1v).1E(1h,1I);o C},4G:q(O,aX){G 3k=C.2J(aX||10);o\'0\'.7h(O-3k.O)+3k},3s:q(){o e4(C)?C.2J():\'1j\'}});$w(\'e5 e6 e7 e8\').1E(q(1B){55.1k[1B]=e9[1B].4F()});q $H(W){o 1t 3Y(W)};G 3Y=2f.2u(2K,(q(){q 8F(1w,I){E(M.2D(I))o 1w;o 1w+\'=\'+aY(24.5y(I))}o{2I:q(W){C.4o=M.8c(W)?W.6s():M.2F(W)},4m:q(1h){18(G 1w 1O C.4o){G I=C.4o[1w],1G=[1w,I];1G.1w=1w;1G.I=I;1h(1G)}},6t:q(1w,I){o C.4o[1w]=I},8G:q(1w){E(C.4o[1w]!==M.1k[1w])o C.4o[1w]},ea:q(1w){G I=C.4o[1w];8H C.4o[1w];o I},6s:q(){o M.2F(C.4o)},4b:q(){o C.5J(\'1w\')},1S:q(){o C.5J(\'I\')},1m:q(I){G 1f=C.7j(q(1G){o 1G.I===I});o 1f&&1f.1w},eb:q(W){o C.2F().56(W)},56:q(W){o 1t 3Y(W).3y(C,q(1s,1G){1s.6t(1G.1w,1G.I);o 1s})},4C:q(){o C.3y([],q(U,1G){G 1w=aY(1G.1w),1S=1G.I;E(1S&&3i 1S==\'W\'){E(M.4D(1S))o U.1V(1S.2S(8F.8d(1w)))}1i U.1g(8F(1w,1S));o U}).2E(\'&\')},2C:q(){o\'#<3Y:{\'+C.2S(q(1G){o 1G.2S(M.2C).2E(\': \')}).2E(\', \')+\'}>\'},3s:q(){o M.3s(C.6s())},2F:q(){o 1t 3Y(C)}}})());3Y.1k.8v=3Y.1k.6s;3Y.aP=$H;G aZ=2f.2u(2K,{2I:q(4p,57,5L){C.4p=4p;C.57=57;C.5L=5L},4m:q(1h){G I=C.4p;1P(C.1H(I)){1h(I);I=I.8l()}},1H:q(I){E(I<C.4p)o 1p;E(C.5L)o I<C.57;o I<=C.57}});G $R=q(4p,57,5L){o 1t aZ(4p,57,5L)};G 1Q={b0:q(){o ag.ah(q(){o 1t b1()},q(){o 1t b2(\'ec.b3\')},q(){o 1t b2(\'ed.b3\')})||1p},8I:0};1Q.5M={6u:[],4m:q(1h){C.6u.4m(1h)},b4:q(4q){E(!C.1H(4q))C.6u.1g(4q)},ee:q(4q){C.6u=C.6u.6r(4q)},7k:q(31,2V,1Y,3o){C.1E(q(4q){E(M.2A(4q[31])){22{4q[31].3r(4q,[2V,1Y,3o])}26(e){}}})}};M.17(1Q.5M,2K);1Q.5M.b4({7l:q(){1Q.8I++},3N:q(){1Q.8I--}});1Q.8J=2f.2u({2I:q(V){C.V={1B:\'6v\',7m:1v,6w:\'7n/x-ef-1y-eg\',8K:\'eh-8\',3B:\'\',5E:1v,8L:1v};M.17(C.V,V||{});C.V.1B=C.V.1B.2b();E(M.3j(C.V.3B))C.V.3B=C.V.3B.7g();1i E(M.8c(C.V.3B))C.V.3B=C.V.3B.6s()}});1Q.58=2f.2u(1Q.8J,{8M:1p,2I:q($4c,2W,V){$4c(V);C.1Y=1Q.b0();C.2V(2W)},2V:q(2W){C.2W=2W;C.1B=C.V.1B;G 3a=M.2F(C.V.3B);E(![\'8G\',\'6v\'].1H(C.1B)){3a[\'ei\']=C.1B;C.1B=\'6v\'}C.3B=3a;E(3a=M.4C(3a)){E(C.1B==\'8G\')C.2W+=(C.2W.1H(\'?\')?\'&\':\'?\')+3a;1i E(/ej|a7|a5/.2R(47.48))3a+=\'&6m=\'}22{G 2y=1t 1Q.8N(C);E(C.V.7l)C.V.7l(2y);1Q.5M.7k(\'7l\',C,2y);C.1Y.ek(C.1B.2o(),C.2W,C.V.7m);E(C.V.7m)C.8O.2B(C).4E(1);C.1Y.7o=C.8P.2B(C);C.b5();C.2c=C.1B==\'6v\'?(C.V.el||3a):1j;C.1Y.em(C.2c);E(!C.V.7m&&C.1Y.b6)C.8P()}26(e){C.59(e)}},8P:q(){G 2X=C.1Y.2X;E(2X>1&&!((2X==4)&&C.8M))C.8O(C.1Y.2X)},b5:q(){G 5a={\'X-eo-ep\':\'b1\',\'X-1e-88\':1e.88,\'eq\':\'4k/er, 4k/7p, 7n/6x, 4k/6x, */*\'};E(C.1B==\'6v\'){5a[\'8Q-1r\']=C.V.6w+(C.V.8K?\'; es=\'+C.V.8K:\'\');E(C.1Y.b6&&(47.48.1f(/78\\/(\\d{4})/)||[0,b7])[1]<b7)5a[\'et\']=\'eu\'}E(3i C.V.b8==\'W\'){G 5N=C.V.b8;E(M.2A(5N.1g))18(G i=0,O=5N.O;i<O;i+=2)5a[5N[i]]=5N[i+1];1i $H(5N).1E(q(1G){5a[1G.1w]=1G.I})}18(G 1d 1O 5a)C.1Y.ev(1d,5a[1d])},5b:q(){G 4I=C.6y();o!4I||(4I>=ew&&4I<ex)},6y:q(){22{o C.1Y.4I||0}26(e){o 0}},8O:q(2X){G 6z=1Q.58.b9[2X],2y=1t 1Q.8N(C);E(6z==\'8R\'){22{C.8M=1v;(C.V[\'5O\'+2y.4I]||C.V[\'5O\'+(C.5b()?\'ey\':\'ez\')]||1e.3g)(2y,2y.7q)}26(e){C.59(e)}G 6w=2y.5P(\'8Q-1r\');E(C.V.8L==\'ba\'||(C.V.8L&&C.7r()&&6w&&6w.1f(/^\\s*(4k|7n)\\/(x-)?(eA|eB)4V(;.*)?\\s*$/i)))C.bb()}22{(C.V[\'5O\'+6z]||1e.3g)(2y,2y.7q);1Q.5M.7k(\'5O\'+6z,C,2y,2y.7q)}26(e){C.59(e)}E(6z==\'8R\'){C.1Y.7o=1e.3g}},7r:q(){G m=C.2W.1f(/^\\s*eC?:\\/\\/[^\\/]*/);o!m||(m[0]==\'#{8S}//#{8T}#{7s}\'.aD({8S:7t.8S,8T:1b.8T,7s:7t.7s?\':\'+7t.7s:\'\'}))},5P:q(1d){22{o C.1Y.8U(1d)||1j}26(e){o 1j}},bb:q(){22{o 7e((C.1Y.3b||\'\').8r())}26(e){C.59(e)}},59:q(8V){(C.V.bc||1e.3g)(C,8V);1Q.5M.7k(\'bc\',C,8V)}});1Q.58.b9=[\'eD\',\'eE\',\'eF\',\'eG\',\'8R\'];1Q.8N=2f.2u({2I:q(2V){C.2V=2V;G 1Y=C.1Y=2V.1Y,2X=C.2X=1Y.2X;E((2X>2&&!1e.1R.3W)||2X==4){C.4I=C.6y();C.8W=C.bd();C.3b=24.5y(1Y.3b);C.7q=C.be()}E(2X==4){G 6x=1Y.bf;C.bf=M.2D(6x)?1j:6x;C.eH=C.bg()}},4I:0,8W:\'\',6y:1Q.58.1k.6y,bd:q(){22{o C.1Y.8W||\'\'}26(e){o\'\'}},5P:1Q.58.1k.5P,eI:q(){22{o C.8X()}26(e){o 1j}},8U:q(1d){o C.1Y.8U(1d)},8X:q(){o C.1Y.8X()},be:q(){G 3o=C.5P(\'X-aC\');E(!3o)o 1j;3o=8k(aj(3o));22{o 3o.5E(C.2V.V.bh||!C.2V.7r())}26(e){C.2V.59(e)}},bg:q(){G V=C.2V.V;E(!V.5E||(V.5E!=\'ba\'&&!(C.5P(\'8Q-1r\')||\'\').1H(\'7n/3o\'))||C.3b.52())o 1j;22{o C.3b.5E(V.bh||!C.2V.7r())}26(e){C.2V.59(e)}}});1Q.bi=2f.2u(1Q.58,{2I:q($4c,3C,2W,V){C.3C={5b:(3C.5b||3C),8Y:(3C.8Y||(3C.5b?1j:3C))};V=M.2F(V);G 3N=V.3N;V.3N=(q(2y,3o){C.bj(2y.3b);E(M.2A(3N))3N(2y,3o)}).2B(C);$4c(2W,V)},bj:q(3b){G 5Q=C.3C[C.5b()?\'5b\':\'8Y\'],V=C.V;E(!V.50)3b=3b.4j();E(5Q=$(5Q)){E(V.5c){E(M.3j(V.5c)){G 5c={};5c[V.5c]=3b;5Q.3D(5c)}1i V.5c(5Q,3b)}1i 5Q.56(3b)}}});1Q.eJ=2f.2u(1Q.8J,{2I:q($4c,3C,2W,V){$4c(V);C.3N=C.V.3N;C.4h=(C.V.4h||2);C.5d=(C.V.5d||1);C.8Z={};C.3C=3C;C.2W=2W;C.4p()},4p:q(){C.V.3N=C.bk.2B(C);C.6j()},8h:q(){C.8Z.V.3N=4A;eK(C.41);(C.3N||1e.3g).3r(C,1q)},bk:q(2y){E(C.V.5d){C.5d=(2y.3b==C.bl?C.5d*C.V.5d:1);C.bl=2y.3b}C.41=C.6j.2B(C).8e(C.5d*C.4h)},6j:q(){C.8Z=1t 1Q.bi(C.3C,C.2W,C.V)}});q $(k){E(1q.O>1){18(G i=0,1Z=[],O=1q.O;i<O;i++)1Z.1g($(1q[i]));o 1Z}E(M.3j(k))k=1b.eL(k);o J.17(k)}E(1e.3K.79){1b.90=q(1u,7u){G U=[];G 91=1b.2P(1u,$(7u)||1b,1j,eM.eN,1j);18(G i=0,O=91.eO;i<O;i++)U.1g(J.17(91.eP(i)));o U}}E(!1D.6A)G 6A={};E(!6A.bm){M.17(6A,{bm:1,eQ:2,bn:3,eR:4,eS:5,eT:6,eU:7,eV:8,eW:9,eX:10,eY:11,eZ:12})}(q(){G k=C.J;C.J=q(15,2p){2p=2p||{};15=15.2b();G 2Y=J.2Y;E(1e.1R.3W&&2p.1d){15=\'<\'+15+\' 1d="\'+2p.1d+\'">\';8H 2p.1d;o J.6B(1b.3X(15),2p)}E(!2Y[15])2Y[15]=J.17(1b.3X(15));o J.6B(2Y[15].f0(1p),2p)};M.17(C.J,k||{});E(k)C.J.1k=k.1k}).2L(1D);J.2Y={};J.1c={92:q(k){o $(k).Y.3E!=\'7v\'},bo:q(k){k=$(k);J[J.92(k)?\'bp\':\'bq\'](k);o k},bp:q(k){k=$(k);k.Y.3E=\'7v\';o k},bq:q(k){k=$(k);k.Y.3E=\'\';o k},br:q(k){k=$(k);k.1W.6C(k);o k},56:q(k,1a){k=$(k);E(1a&&1a.3F)1a=1a.3F();E(M.4d(1a))o k.56().3D(1a);1a=M.4e(1a);k.51=1a.4j();1a.50.2B(1a).4E();o k},1T:q(k,1a){k=$(k);E(1a&&1a.3F)1a=1a.3F();1i E(!M.4d(1a)){1a=M.4e(1a);G 93=k.f1.f2();93.f3(k);1a.50.2B(1a).4E();1a=93.f4(1a.4j())}k.1W.94(1a,k);o k},3D:q(k,3O){k=$(k);E(M.3j(3O)||M.4Z(3O)||M.4d(3O)||(3O&&(3O.3F||3O.4e)))3O={5e:3O};G 1a,3D,15,3n;18(G 1x 1O 3O){1a=3O[1x];1x=1x.2b();3D=J.5R[1x];E(1a&&1a.3F)1a=1a.3F();E(M.4d(1a)){3D(k,1a);3P}1a=M.4e(1a);15=((1x==\'53\'||1x==\'7w\')?k.1W:k).15.2o();3n=J.7x(15,1a.4j());E(1x==\'2q\'||1x==\'7w\')3n.4n();3n.1E(3D.8d(k));1a.50.2B(1a).4E()}o k},4z:q(k,1L,2p){k=$(k);E(M.4d(1L))$(1L).6B(2p||{});1i E(M.3j(1L))1L=1t J(1L,2p);1i 1L=1t J(\'1N\',1L);E(k.1W)k.1W.94(1L,k);1L.5H(k);o 1L},2C:q(k){k=$(k);G 1s=\'<\'+k.15.2b();$H({\'1o\':\'1o\',\'1l\':\'6D\'}).1E(q(1G){G 1z=1G.3M(),1X=1G.2x();G I=(k[1z]||\'\').2J();E(I)1s+=\' \'+1X+\'=\'+I.2C(1v)});o 1s+\'>\'},7y:q(k,1z){k=$(k);G 1Z=[];1P(k=k[1z])E(k.3t==1)1Z.1g(J.17(k));o 1Z},5S:q(k){o $(k).7y(\'1W\')},bs:q(k){o $(k).2G("*")},bt:q(k){k=$(k).5T;1P(k&&k.3t!=1)k=k.4r;o $(k)},bu:q(k){E(!(k=$(k).5T))o[];1P(k&&k.3t!=1)k=k.4r;E(k)o[k].1V($(k).4J());o[]},5U:q(k){o $(k).7y(\'bv\')},4J:q(k){o $(k).7y(\'4r\')},f5:q(k){k=$(k);o k.5U().4n().1V(k.4J())},1f:q(k,42){E(M.3j(42))42=1t 14(42);o 42.1f($(k))},f6:q(k,1u,1m){k=$(k);E(1q.O==1)o $(k.1W);G 5S=k.5S();o M.4Z(1u)?5S[1u]:14.5V(5S,1u,1m)},f7:q(k,1u,1m){k=$(k);E(1q.O==1)o k.bt();o M.4Z(1u)?k.bs()[1u]:J.2G(k,1u)[1m||0]},f8:q(k,1u,1m){k=$(k);E(1q.O==1)o $(14.29.6E(k));G 5U=k.5U();o M.4Z(1u)?5U[1u]:14.5V(5U,1u,1m)},6F:q(k,1u,1m){k=$(k);E(1q.O==1)o $(14.29.6G(k));G 4J=k.4J();o M.4Z(1u)?4J[1u]:14.5V(4J,1u,1m)},2G:q(){G 1U=$A(1q),k=$(1U.4W());o 14.7z(k,1U)},5f:q(){G 1U=$A(1q),k=$(1U.4W());o 14.7z(k.1W,1U).6r(k)},95:q(k){k=$(k);G 1o=k.5g(\'1o\'),5C=1q.5A;E(1o)o 1o;do{1o=\'f9\'+5C.bw++}1P($(1o));k.6B(\'1o\',1o);o 1o},5g:q(k,1d){k=$(k);E(1e.1R.3W){G t=J.3Q.7A;E(t.1S[1d])o t.1S[1d](k,1d);E(t.3u[1d])1d=t.3u[1d];E(1d.1H(\':\')){o(!k.2p||!k.2p[1d])?1j:k.2p[1d].I}}o k.96(1d)},6B:q(k,1d,I){k=$(k);G 2p={},t=J.3Q.6H;E(3i 1d==\'W\')2p=1d;1i 2p[1d]=M.2D(I)?1v:I;18(G 2d 1O 2p){1d=t.3u[2d]||2d;I=2p[2d];E(t.1S[2d])1d=t.1S[2d](k,I);E(I===1p||I===1j)k.97(1d);1i E(I===1v)k.bx(1d,1d);1i k.bx(1d,I)}o k},by:q(k){o $(k).5W().3c},bz:q(k){o $(k).5W().2j},6I:q(k){o 1t J.7B(k)},7C:q(k,1l){E(!(k=$(k)))o;G 7D=k.1l;o(7D.O>0&&(7D==1l||1t 4g("(^|\\\\s)"+1l+"(\\\\s|$)").2R(7D)))},bA:q(k,1l){E(!(k=$(k)))o;E(!k.7C(1l))k.1l+=(k.1l?\' \':\'\')+1l;o k},bB:q(k,1l){E(!(k=$(k)))o;k.1l=k.1l.1T(1t 4g("(^|\\\\s+)"+1l+"(\\\\s+|$)"),\' \').4i();o k},fa:q(k,1l){E(!(k=$(k)))o;o k[k.7C(1l)?\'bB\':\'bA\'](1l)},fb:q(k){k=$(k);G L=k.5T;1P(L){G bC=L.4r;E(L.3t==3&&!/\\S/.2R(L.4l))k.6C(L);L=bC}o k},5F:q(k){o $(k).51.52()},7E:q(k,3L){k=$(k),3L=$(3L);E(k.bD)o(k.bD(3L)&8)===8;E(3L.5h)o 3L.5h(k)&&3L!==k;1P(k=k.1W)E(k==3L)o 1v;o 1p},bE:q(k){k=$(k);G 5X=k.4s();1D.bE(5X[0],5X[1]);o k},2e:q(k,Y){k=$(k);Y=Y==\'98\'?\'7F\':Y.8m();G I=k.Y[Y];E(!I||I==\'6J\'){G 99=1b.fc.fd(k,1j);I=99?99[Y]:1j}E(Y==\'3R\')o I?5i(I):1.0;o I==\'6J\'?1j:I},fe:q(k){o $(k).2e(\'3R\')},5Y:q(k,4K){k=$(k);G 9a=k.Y,1f;E(M.3j(4K)){k.Y.9b+=\';\'+4K;o 4K.1H(\'3R\')?k.5Z(4K.1f(/3R:\\s*(\\d?\\.?\\d*)/)[1]):k}18(G 1z 1O 4K)E(1z==\'3R\')k.5Z(4K[1z]);1i 9a[(1z==\'98\'||1z==\'7F\')?(M.2D(9a.9c)?\'7F\':\'9c\'):1z]=4K[1z];o k},5Z:q(k,I){k=$(k);k.Y.3R=(I==1||I===\'\')?\'\':(I<0.7G)?0:I;o k},5W:q(k){k=$(k);G 3E=k.2e(\'3E\');E(3E!=\'7v\'&&3E!=1j)o{2j:k.60,3c:k.61};G 43=k.Y;G bF=43.9d;G bG=43.1x;G bH=43.3E;43.9d=\'5j\';43.1x=\'62\';43.3E=\'ff\';G bI=k.bJ;G bK=k.bL;43.3E=bH;43.1x=bG;43.9d=bF;o{2j:bI,3c:bK}},fg:q(k){k=$(k);G 5X=J.2e(k,\'1x\');E(5X==\'63\'||!5X){k.9e=1v;k.Y.1x=\'6K\';E(1e.1R.49){k.Y.2q=0;k.Y.2w=0}}o k},fh:q(k){k=$(k);E(k.9e){k.9e=4A;k.Y.1x=k.Y.2q=k.Y.2w=k.Y.5e=k.Y.5K=\'\'}o k},fi:q(k){k=$(k);E(k.5k)o k;k.5k=J.2e(k,\'9f\')||\'6J\';E(k.5k!==\'5j\')k.Y.9f=\'5j\';o k},fj:q(k){k=$(k);E(!k.5k)o k;k.Y.9f=k.5k==\'6J\'?\'\':k.5k;k.5k=1j;o k},4s:q(k){G 2M=0,2N=0;do{2M+=k.5l||0;2N+=k.5m||0;k=k.2O}1P(k);o J.4t(2N,2M)},6L:q(k){G 2M=0,2N=0;do{2M+=k.5l||0;2N+=k.5m||0;k=k.2O;E(k){E(k.15.2o()==\'bM\')2h;G p=J.2e(k,\'1x\');E(p!==\'63\')2h}}1P(k);o J.4t(2N,2M)},9g:q(k){k=$(k);E(k.2e(\'1x\')==\'62\')o k;G 9h=k.6L();G 2q=9h[1];G 2w=9h[0];G 2j=k.bJ;G 3c=k.bL;k.bN=2w-5i(k.Y.2w||0);k.bO=2q-5i(k.Y.2q||0);k.bP=k.Y.2j;k.bQ=k.Y.3c;k.Y.1x=\'62\';k.Y.2q=2q+\'3p\';k.Y.2w=2w+\'3p\';k.Y.2j=2j+\'3p\';k.Y.3c=3c+\'3p\';o k},9i:q(k){k=$(k);E(k.2e(\'1x\')==\'6K\')o k;k.Y.1x=\'6K\';G 2q=5i(k.Y.2q||0)-(k.bO||0);G 2w=5i(k.Y.2w||0)-(k.bN||0);k.Y.2q=2q+\'3p\';k.Y.2w=2w+\'3p\';k.Y.3c=k.bQ;k.Y.2j=k.bP;o k},9j:q(k){G 2M=0,2N=0;do{2M+=k.4u||0;2N+=k.4v||0;k=k.1W}1P(k);o J.4t(2N,2M)},64:q(k){E(k.2O)o $(k.2O);E(k==1b.2c)o $(k);1P((k=k.1W)&&k!=1b.2c)E(J.2e(k,\'1x\')!=\'63\')o $(k);o $(1b.2c)},6M:q(9k){G 2M=0,2N=0;G k=9k;do{2M+=k.5l||0;2N+=k.5m||0;E(k.2O==1b.2c&&J.2e(k,\'1x\')==\'62\')2h}1P(k=k.2O);k=9k;do{E(!1e.1R.49||(k.15&&(k.15.2o()==\'bM\'))){2M-=k.4u||0;2N-=k.4v||0}}1P(k=k.1W);o J.4t(2N,2M)},bR:q(k,25){G V=M.17({bS:1v,bT:1v,bU:1v,bV:1v,5l:0,5m:0},1q[2]||{});25=$(25);G p=25.6M();k=$(k);G 65=[0,0];G 2Q=1j;E(J.2e(k,\'1x\')==\'62\'){2Q=k.64();65=2Q.6M()}E(2Q==1b.2c){65[0]-=1b.2c.5m;65[1]-=1b.2c.5l}E(V.bS)k.Y.2w=(p[0]-65[0]+V.5m)+\'3p\';E(V.bT)k.Y.2q=(p[1]-65[1]+V.5l)+\'3p\';E(V.bU)k.Y.2j=25.60+\'3p\';E(V.bV)k.Y.3c=25.61+\'3p\';o k}};J.1c.95.bw=1;M.17(J.1c,{fk:J.1c.2G,fl:J.1c.bu});J.3Q={6H:{3u:{1l:\'6D\',bW:\'18\'},1S:{}}};E(1e.1R.49){J.1c.2e=J.1c.2e.4z(q(2Z,k,Y){4Y(Y){2g\'2w\':2g\'2q\':2g\'5K\':2g\'5e\':E(2Z(k,\'1x\')===\'63\')o 1j;2g\'3c\':2g\'2j\':E(!J.92(k))o 1j;G 7H=bX(2Z(k,Y),10);E(7H!==k[\'3d\'+Y.6l()])o 7H+\'3p\';G 3h;E(Y===\'3c\'){3h=[\'7I-2q-2j\',\'7J-2q\',\'7J-5e\',\'7I-5e-2j\']}1i{3h=[\'7I-2w-2j\',\'7J-2w\',\'7J-5K\',\'7I-5K-2j\']}o 3h.3y(7H,q(2T,1z){G 9l=2Z(k,1z);o 9l===1j?2T:2T-bX(9l,10)})+\'3p\';66:o 2Z(k,Y)}});J.1c.5g=J.1c.5g.4z(q(2Z,k,1X){E(1X===\'7K\')o k.7K;o 2Z(k,1X)})}1i E(1e.1R.3W){J.1c.64=J.1c.64.4z(q(2Z,k){k=$(k);22{k.2O}26(e){o $(1b.2c)}G 1x=k.2e(\'1x\');E(1x!==\'63\')o 2Z(k);k.5Y({1x:\'6K\'});G I=2Z(k);k.5Y({1x:1x});o I});$w(\'6L 6M\').1E(q(1B){J.1c[1B]=J.1c[1B].4z(q(2Z,k){k=$(k);22{k.2O}26(e){o J.4t(0,0)}G 1x=k.2e(\'1x\');E(1x!==\'63\')o 2Z(k);G 2O=k.64();E(2O&&2O.2e(\'1x\')===\'fm\')2O.5Y({9m:1});k.5Y({1x:\'6K\'});G I=2Z(k);k.5Y({1x:1x});o I})});J.1c.4s=J.1c.4s.4z(q(2Z,k){22{k.2O}26(e){o J.4t(0,0)}o 2Z(k)});J.1c.2e=q(k,Y){k=$(k);Y=(Y==\'98\'||Y==\'7F\')?\'9c\':Y.8m();G I=k.Y[Y];E(!I&&k.5n)I=k.5n[Y];E(Y==\'3R\'){E(I=(k.2e(\'2i\')||\'\').1f(/9n\\(3R=(.*)\\)/))E(I[1])o 5i(I[1])/bY;o 1.0}E(I==\'6J\'){E((Y==\'2j\'||Y==\'3c\')&&(k.2e(\'3E\')!=\'7v\'))o k[\'3d\'+Y.6l()]+\'3p\';o 1j}o I};J.1c.5Z=q(k,I){q 9o(2i){o 2i.1T(/9n\\([^\\)]*\\)/gi,\'\')}k=$(k);G 5n=k.5n;E((5n&&!5n.fn)||(!5n&&k.Y.9m==\'bZ\'))k.Y.9m=1;G 2i=k.2e(\'2i\'),Y=k.Y;E(I==1||I===\'\'){(2i=9o(2i))?Y.2i=2i:Y.97(\'2i\');o k}1i E(I<0.7G)I=0;Y.2i=9o(2i)+\'9n(3R=\'+(I*bY)+\')\';o k};J.3Q={7A:{3u:{\'6D\':\'1l\',\'18\':\'bW\'},1S:{7L:q(k,1X){o k.96(1X,2)},c0:q(k,1X){G L=k.c1(1X);o L?L.I:""},2r:q(k,1X){1X=k.96(1X);o 1X?1X.2J().3w(23,-2):1j},6N:q(k,1X){o $(k).3S(1X)?1X:1j},Y:q(k){o k.Y.9b.2b()},7K:q(k){o k.7K}}}};J.3Q.6H={3u:M.17({fo:\'fp\',fq:\'fr\'},J.3Q.7A.3u),1S:{3T:q(k,I){k.3T=!!I},Y:q(k,I){k.Y.9b=I?I:\'\'}}};J.3Q.9p={};$w(\'fs ft fu fv fw 7M \'+\'fx fy fz fA fB\').1E(q(2d){J.3Q.6H.3u[2d.2b()]=2d;J.3Q.9p[2d.2b()]=2d});(q(v){M.17(v,{c2:v.7L,c3:v.7L,1r:v.7L,67:v.c0,3G:v.6N,3T:v.6N,fC:v.6N,fD:v.6N,fE:v.2r,c4:v.2r,fF:v.2r,fG:v.2r,fH:v.2r,fI:v.2r,fJ:v.2r,fK:v.2r,fL:v.2r,fM:v.2r,fN:v.2r,fO:v.2r,fP:v.2r,fQ:v.2r,fR:v.2r,fS:v.2r,fT:v.2r,fU:v.2r})})(J.3Q.7A.1S)}1i E(1e.1R.78&&/fV:1\\.8\\.0/.2R(47.48)){J.1c.5Z=q(k,I){k=$(k);k.Y.3R=(I==1)?0.fW:(I===\'\')?\'\':(I<0.7G)?0:I;o k}}1i E(1e.1R.4a){J.1c.5Z=q(k,I){k=$(k);k.Y.3R=(I==1||I===\'\')?\'\':(I<0.7G)?0:I;E(I==1)E(k.15.2o()==\'c5\'&&k.2j){k.2j++;k.2j--}1i 22{G n=1b.aG(\' \');k.5H(n);k.6C(n)}26(e){}o k};J.1c.4s=q(k){G 2M=0,2N=0;do{2M+=k.5l||0;2N+=k.5m||0;E(k.2O==1b.2c)E(J.2e(k,\'1x\')==\'62\')2h;k=k.2O}1P(k);o J.4t(2N,2M)}}E(1e.1R.3W||1e.1R.49){J.1c.56=q(k,1a){k=$(k);E(1a&&1a.3F)1a=1a.3F();E(M.4d(1a))o k.56().3D(1a);1a=M.4e(1a);G 15=k.15.2o();E(15 1O J.5R.4L){$A(k.3n).1E(q(L){k.6C(L)});J.7x(15,1a.4j()).1E(q(L){k.5H(L)})}1i k.51=1a.4j();1a.50.2B(1a).4E();o k}}E(\'c6\'1O 1b.3X(\'1N\')){J.1c.1T=q(k,1a){k=$(k);E(1a&&1a.3F)1a=1a.3F();E(M.4d(1a)){k.1W.94(1a,k);o k}1a=M.4e(1a);G 2Q=k.1W,15=2Q.15.2o();E(J.5R.4L[15]){G 4r=k.6F();G 9q=J.7x(15,1a.4j());2Q.6C(k);E(4r)9q.1E(q(L){2Q.7N(L,4r)});1i 9q.1E(q(L){2Q.5H(L)})}1i k.c6=1a.4j();1a.50.2B(1a).4E();o k}}J.4t=q(l,t){G 1s=[l,t];1s.2w=l;1s.2q=t;o 1s};J.7x=q(15,7p){G 1N=1t J(\'1N\'),t=J.5R.4L[15];E(t){1N.51=t[0]+7p+t[1];t[2].7h(q(){1N=1N.5T})}1i 1N.51=7p;o $A(1N.3n)};J.5R={53:q(k,L){k.1W.7N(L,k)},2q:q(k,L){k.7N(L,k.5T)},5e:q(k,L){k.5H(L)},7w:q(k,L){k.1W.7N(L,k.4r)},4L:{fX:[\'<4M>\',\'</4M>\',1],7O:[\'<4M><68>\',\'</68></4M>\',2],c7:[\'<4M><68><7P>\',\'</7P></68></4M>\',3],9r:[\'<4M><68><7P><c8>\',\'</c8></7P></68></4M>\',4],c9:[\'<2G>\',\'</2G>\',1]}};(q(){M.17(C.4L,{ca:C.4L.7O,cb:C.4L.7O,cc:C.4L.9r})}).2L(J.5R);J.1c.7Q={3S:q(k,1X){1X=J.3Q.9p[1X]||1X;G L=$(k).c1(1X);o!!(L&&L.fY)}};J.1c.3H={};M.17(J,J.1c);E(!1e.3K.6f&&1b.3X(\'1N\')[\'4U\']){1D.6g={};1D.6g.1k=1b.3X(\'1N\')[\'4U\'];1e.3K.6f=1v}J.17=(q(){E(1e.3K.7a)o 1e.K;G 1c={},3H=J.1c.3H;G 17=M.17(q(k){E(!k||k.7R||k.3t!=1||k==1D)o k;G 2H=M.2F(1c),15=k.15.2o(),1z,I;E(3H[15])M.17(2H,3H[15]);18(1z 1O 2H){I=2H[1z];E(M.2A(I)&&!(1z 1O k))k[1z]=I.4F()}k.7R=1e.3g;o k},{7S:q(){E(!1e.3K.6f){M.17(1c,J.1c);M.17(1c,J.1c.7Q)}}});17.7S();o 17})();J.3S=q(k,1X){E(k.3S)o k.3S(1X);o J.1c.7Q.3S(k,1X)};J.6h=q(2H){G F=1e.3K,T=J.1c.3H;E(!2H){M.17(1C,1C.1c);M.17(1C.J,1C.J.1c);M.17(J.1c.3H,{"fZ":M.2F(1C.1c),"g0":M.2F(1C.J.1c),"c9":M.2F(1C.J.1c),"cd":M.2F(1C.J.1c)})}E(1q.O==2){G 15=2H;2H=1q[1]}E(!15)M.17(J.1c,2H||{});1i{E(M.4D(15))15.1E(17);1i 17(15)}q 17(15){15=15.2o();E(!J.1c.3H[15])J.1c.3H[15]={};M.17(J.1c.3H[15],2H)}q 7T(2H,5x,7U){7U=7U||1p;18(G 1z 1O 2H){G I=2H[1z];E(!M.2A(I))3P;E(!7U||!(1z 1O 5x))5x[1z]=I.4F()}}q ce(15){G 1M;G 9s={"g1":"g2","cd":"g3","P":"g4","g5":"g6","g7":"g8","g9":"ga","gb":"gc","gd":"ge","gf":"69","gg":"69","gh":"69","gj":"69","gk":"69","gl":"69","Q":"gm","gn":"cf","go":"cf","A":"gp","c5":"gq","gr":"gs","gu":"cg","gv":"cg","ca":"9t","cb":"9t","7O":"9t","c7":"gw","cc":"ch","9r":"ch","gx":"gy","gz":"gA"};E(9s[15])1M=\'9u\'+9s[15]+\'J\';E(1D[1M])o 1D[1M];1M=\'9u\'+15+\'J\';E(1D[1M])o 1D[1M];1M=\'9u\'+15.6l()+\'J\';E(1D[1M])o 1D[1M];1D[1M]={};1D[1M].1k=1b.3X(15)[\'4U\'];o 1D[1M]}E(F.6f){7T(J.1c,6g.1k);7T(J.1c.7Q,6g.1k,1v)}E(F.7a){18(G 9v 1O J.1c.3H){G 1M=ce(9v);E(M.2D(1M))3P;7T(T[9v],1M.1k)}}M.17(J,J.1c);8H J.3H;E(J.17.7S)J.17.7S();J.2Y={}};1b.gB={5W:q(){G 6O={},B=1e.1R;$w(\'2j 3c\').1E(q(d){G D=d.6l();E(B.4a&&!1b.2P){6O[d]=5C[\'gC\'+D]}1i E(B.49&&5i(1D.gD.gE())<9.5){6O[d]=1b.2c[\'ci\'+D]}1i{6O[d]=1b.5o[\'ci\'+D]}});o 6O},bz:q(){o C.5W().2j},by:q(){o C.5W().3c},gF:q(){o J.4t(1D.cj||1b.5o.4v||1b.2c.4v,1D.ck||1b.5o.4u||1b.2c.4u)}};G 14=2f.2u({2I:q(1u){C.1u=1u.4i();E(C.cl()){C.4N=\'cm\'}1i E(C.co()){C.4N=\'2s\';C.cp()}1i{C.4N="bZ";C.cq()}},co:q(){E(!1e.3K.79)o 1p;G e=C.1u;E(1e.1R.4a&&(e.1H("-2z-1r")||e.1H(":5F")))o 1p;E((/(\\[[\\w-]*?:|:3T)/).2R(e))o 1p;o 1v},cl:q(){E(!1e.3K.a8)o 1p;E(!14.9w)14.9w=1t J(\'1N\');22{14.9w.a9(C.1u)}26(e){o 1p}o 1v},cq:q(){G e=C.1u,4w=14.6P,h=14.29,c=14.6q,3I,p,m;E(14.5p[e]){C.3U=14.5p[e];o}C.3U=["C.3U = q(1n) {","G r = 1n, h = 14.29, c = 1p, n;"];1P(e&&3I!=e&&(/\\S/).2R(e)){3I=e;18(G i 1O 4w){p=4w[i];E(m=e.1f(p)){C.3U.1g(M.2A(c[i])?c[i](m):1t 32(c[i]).2P(m));e=e.1T(m[0],\'\');2h}}}C.3U.1g("o h.9x(n);\\n}");7e(C.3U.2E(\'\\n\'));14.5p[C.1u]=C.3U},cp:q(){G e=C.1u,4w=14.6P,x=14.2s,3I,m;E(14.5p[e]){C.2s=14.5p[e];o}C.3U=[\'.//*\'];1P(e&&3I!=e&&(/\\S/).2R(e)){3I=e;18(G i 1O 4w){E(m=e.1f(4w[i])){C.3U.1g(M.2A(x[i])?x[i](m):1t 32(x[i]).2P(m));e=e.1T(m[0],\'\');2h}}}C.2s=C.3U.2E(\'\');14.5p[C.1u]=C.2s},7V:q(1n){1n=1n||1b;G e=C.1u,U;4Y(C.4N){2g\'cm\':E(1n!==1b){G cr=1n.1o,1o=$(1n).95();e="#"+1o+" "+e}U=$A(1n.gG(e)).2S(J.17);1n.1o=cr;o U;2g\'2s\':o 1b.90(C.2s,1n);66:o C.3U(1n)}},1f:q(k){C.9y=[];G e=C.1u,4w=14.6P,as=14.9z;G 3I,p,m;1P(e&&3I!==e&&(/\\S/).2R(e)){3I=e;18(G i 1O 4w){p=4w[i];E(m=e.1f(p)){E(as[i]){C.9y.1g([i,M.2F(m)]);e=e.1T(m[0],\'\')}1i{o C.7V(1b).1H(k)}}}}G 1f=1v,1d,2t;18(G i=0,7W;7W=C.9y[i];i++){1d=7W[0],2t=7W[1];E(!14.9z[1d](k,2t)){1f=1p;2h}}o 1f},2J:q(){o C.1u},2C:q(){o"#<14:"+C.1u.2C()+">"}});M.17(14,{5p:{},2s:{4O:"//*",1J:"/*",5f:"/6Q-4P::*[1]",6R:\'/6Q-4P::*\',15:q(m){E(m[1]==\'*\')o\'\';o"[cs-1d()=\'"+m[1].2b()+"\' ct cs-1d()=\'"+m[1].2o()+"\']"},1l:"[5h(1V(\' \', @6D, \' \'), \' #{1} \')]",1o:"[@1o=\'#{1}\']",6a:q(m){m[1]=m[1].2b();o 1t 32("[@#{1}]").2P(m)},2d:q(m){m[1]=m[1].2b();m[3]=m[5]||m[6];o 1t 32(14.2s.6S[m[2]]).2P(m)},6T:q(m){G h=14.2s.2k[m[1]];E(!h)o\'\';E(M.2A(h))o h(m);o 1t 32(14.2s.2k[m[1]]).2P(m)},6S:{\'=\':"[@#{1}=\'#{3}\']",\'!=\':"[@#{1}!=\'#{3}\']",\'^=\':"[gH-gI(@#{1}, \'#{3}\')]",\'$=\':"[5D(@#{1}, (3k-O(@#{1}) - 3k-O(\'#{3}\') + 1))=\'#{3}\']",\'*=\':"[5h(@#{1}, \'#{3}\')]",\'~=\':"[5h(1V(\' \', @#{1}, \' \'), \' #{3} \')]",\'|=\':"[5h(1V(\'-\', @#{1}, \'-\'), \'-#{3}-\')]"},2k:{\'3M-1J\':\'[4Q(9A-4P::*)]\',\'2x-1J\':\'[4Q(6Q-4P::*)]\',\'6U-1J\':\'[4Q(9A-4P::* ct 6Q-4P::*)]\',\'5F\':"[3x(*) = 0 6V (3x(4k()) = 0)]",\'3T\':"[@3T]",\'3G\':"[(@3G) 6V (@1r!=\'5j\')]",\'cu\':"[4Q(@3G) 6V (@1r!=\'5j\')]",\'4Q\':q(m){G e=m[6],p=14.6P,x=14.2s,3I,v;G 9B=[];1P(e&&3I!=e&&(/\\S/).2R(e)){3I=e;18(G i 1O p){E(m=e.1f(p[i])){v=M.2A(x[i])?x[i](m):1t 32(x[i]).2P(m);9B.1g("("+v.5D(1,v.O-1)+")");e=e.1T(m[0],\'\');2h}}}o"[4Q("+9B.2E(" 6V ")+")]"},\'20-1J\':q(m){o 14.2s.2k.20("(3x(./9A-4P::*) + 1) ",m)},\'20-2x-1J\':q(m){o 14.2s.2k.20("(3x(./6Q-4P::*) + 1) ",m)},\'20-2z-1r\':q(m){o 14.2s.2k.20("1x() ",m)},\'20-2x-2z-1r\':q(m){o 14.2s.2k.20("(2x() + 1 - 1x()) ",m)},\'3M-2z-1r\':q(m){m[6]="1";o 14.2s.2k[\'20-2z-1r\'](m)},\'2x-2z-1r\':q(m){m[6]="1";o 14.2s.2k[\'20-2x-2z-1r\'](m)},\'6U-2z-1r\':q(m){G p=14.2s.2k;o p[\'3M-2z-1r\'](m)+p[\'2x-2z-1r\'](m)},20:q(6b,m){G 44,1K=m[6],9C;E(1K==\'cv\')1K=\'2n+0\';E(1K==\'cw\')1K=\'2n+1\';E(44=1K.1f(/^(\\d+)$/))o\'[\'+6b+"= "+44[1]+\']\';E(44=1K.1f(/^(-?\\d*)?n(([+-])(\\d+))?/)){E(44[1]=="-")44[1]=-1;G a=44[1]?55(44[1]):1;G b=44[2]?55(44[2]):0;9C="[((#{6b} - #{b}) gJ #{a} = 0) 6V "+"((#{6b} - #{b}) 1N #{a} >= 0)]";o 1t 32(9C).2P({6b:6b,a:a,b:b})}}}},6q:{15:\'n = h.15(n, r, "#{1}", c); c = 1p;\',1l:\'n = h.1l(n, r, "#{1}", c); c = 1p;\',1o:\'n = h.1o(n, r, "#{1}", c); c = 1p;\',6a:\'n = h.6a(n, r, "#{1}", c); c = 1p;\',2d:q(m){m[3]=(m[5]||m[6]);o 1t 32(\'n = h.2d(n, r, "#{1}", "#{3}", "#{2}", c); c = 1p;\').2P(m)},6T:q(m){E(m[6])m[6]=m[6].1T(/"/g,\'\\\\"\');o 1t 32(\'n = h.6T(n, "#{1}", "#{6}", r, c); c = 1p;\').2P(m)},4O:\'c = "4O";\',1J:\'c = "1J";\',5f:\'c = "5f";\',6R:\'c = "6R";\'},6P:{6R:/^\\s*~\\s*/,1J:/^\\s*>\\s*/,5f:/^\\s*\\+\\s*/,4O:/^\\s/,15:/^\\s*(\\*|[\\w\\-]+)(\\b|$)?/,1o:/^#([\\w\\-\\*]+)(\\b|$)/,1l:/^\\.([\\w\\-\\*]+)(\\b|$)/,6T:/^:((3M|2x|20|20-2x|6U)(-1J|-2z-1r)|5F|3T|(en|gK)gL|4Q)(\\((.*?)\\))?(\\b|$|(?=\\s|[:+~>]))/,6a:/^\\[((?:[\\w]+:)?[\\w]+)\\]/,2d:/\\[((?:[\\w-]*:)?[\\w-]+)\\s*(?:([!^$*~|]?=)\\s*(([\'"])([^\\4]*?)\\4|([^\'"][^\\]]*?)))?\\]/},9z:{15:q(k,2t){o 2t[1].2o()==k.15.2o()},1l:q(k,2t){o J.7C(k,2t[1])},1o:q(k,2t){o k.1o===2t[1]},6a:q(k,2t){o J.3S(k,2t[1])},2d:q(k,2t){G 4l=J.5g(k,2t[1]);o 4l&&14.6S[2t[2]](4l,2t[5]||2t[6])}},29:{1V:q(a,b){18(G i=0,L;L=b[i];i++)a.1g(L);o a},7X:q(N){G cx=1e.3g;18(G i=0,L;L=N[i];i++)L.3V=cx;o N},5q:q(N){18(G i=0,L;L=N[i];i++)L.3V=4A;o N},1m:q(1W,4n,6W){1W.3V=1e.3g;E(4n){18(G N=1W.3n,i=N.O-1,j=1;i>=0;i--){G L=N[i];E(L.3t==1&&(!6W||L.3V))L.7Y=j++}}1i{18(G i=0,j=1,N=1W.3n;L=N[i];i++)E(L.3t==1&&(!6W||L.3V))L.7Y=j++}},9x:q(N){E(N.O==0)o N;G U=[],n;18(G i=0,l=N.O;i<l;i++)E(!(n=N[i]).3V){n.3V=1e.3g;U.1g(J.17(n))}o 14.29.5q(U)},4O:q(N){G h=14.29;18(G i=0,U=[],L;L=N[i];i++)h.1V(U,L.4x(\'*\'));o U},1J:q(N){G h=14.29;18(G i=0,U=[],L;L=N[i];i++){18(G j=0,1J;1J=L.3n[j];j++)E(1J.3t==1&&1J.15!=\'!\')U.1g(1J)}o U},5f:q(N){18(G i=0,U=[],L;L=N[i];i++){G 6F=C.6G(L);E(6F)U.1g(6F)}o U},6R:q(N){G h=14.29;18(G i=0,U=[],L;L=N[i];i++)h.1V(U,J.4J(L));o U},6G:q(L){1P(L=L.4r)E(L.3t==1)o L;o 1j},6E:q(L){1P(L=L.bv)E(L.3t==1)o L;o 1j},15:q(N,1n,15,2a){G cy=15.2o();G U=[],h=14.29;E(N){E(2a){E(2a=="4O"){18(G i=0,L;L=N[i];i++)h.1V(U,L.4x(15));o U}1i N=C[2a](N);E(15=="*")o N}18(G i=0,L;L=N[i];i++)E(L.15.2o()===cy)U.1g(L);o U}1i o 1n.4x(15)},1o:q(N,1n,1o,2a){G 3e=$(1o),h=14.29;E(!3e)o[];E(!N&&1n==1b)o[3e];E(N){E(2a){E(2a==\'1J\'){18(G i=0,L;L=N[i];i++)E(3e.1W==L)o[3e]}1i E(2a==\'4O\'){18(G i=0,L;L=N[i];i++)E(J.7E(3e,L))o[3e]}1i E(2a==\'5f\'){18(G i=0,L;L=N[i];i++)E(14.29.6E(3e)==L)o[3e]}1i N=h[2a](N)}18(G i=0,L;L=N[i];i++)E(L==3e)o[3e];o[]}o(3e&&J.7E(3e,1n))?[3e]:[]},1l:q(N,1n,1l,2a){E(N&&2a)N=C[2a](N);o 14.29.cz(N,1n,1l)},cz:q(N,1n,1l){E(!N)N=14.29.4O([1n]);G cA=\' \'+1l+\' \';18(G i=0,U=[],L,6X;L=N[i];i++){6X=L.1l;E(6X.O==0)3P;E(6X==1l||(\' \'+6X+\' \').1H(cA))U.1g(L)}o U},6a:q(N,1n,2d,2a){E(!N)N=1n.4x("*");E(N&&2a)N=C[2a](N);G U=[];18(G i=0,L;L=N[i];i++)E(J.3S(L,2d))U.1g(L);o U},2d:q(N,1n,2d,I,cB,2a){E(!N)N=1n.4x("*");E(N&&2a)N=C[2a](N);G 2l=14.6S[cB],U=[];18(G i=0,L;L=N[i];i++){G 4l=J.5g(L,2d);E(4l===1j)3P;E(2l(4l,I))U.1g(L)}o U},6T:q(N,1d,I,1n,2a){E(N&&2a)N=C[2a](N);E(!N)N=1n.4x("*");o 14.2k[1d](N,I,1n)}},2k:{\'3M-1J\':q(N,I,1n){18(G i=0,U=[],L;L=N[i];i++){E(14.29.6E(L))3P;U.1g(L)}o U},\'2x-1J\':q(N,I,1n){18(G i=0,U=[],L;L=N[i];i++){E(14.29.6G(L))3P;U.1g(L)}o U},\'6U-1J\':q(N,I,1n){G h=14.29;18(G i=0,U=[],L;L=N[i];i++)E(!h.6E(L)&&!h.6G(L))U.1g(L);o U},\'20-1J\':q(N,1K,1n){o 14.2k.20(N,1K,1n)},\'20-2x-1J\':q(N,1K,1n){o 14.2k.20(N,1K,1n,1v)},\'20-2z-1r\':q(N,1K,1n){o 14.2k.20(N,1K,1n,1p,1v)},\'20-2x-2z-1r\':q(N,1K,1n){o 14.2k.20(N,1K,1n,1v,1v)},\'3M-2z-1r\':q(N,1K,1n){o 14.2k.20(N,"1",1n,1p,1v)},\'2x-2z-1r\':q(N,1K,1n){o 14.2k.20(N,"1",1n,1v,1v)},\'6U-2z-1r\':q(N,1K,1n){G p=14.2k;o p[\'2x-2z-1r\'](p[\'3M-2z-1r\'](N,1K,1n),1K,1n)},cC:q(a,b,cD){E(a==0)o b>0?[b]:[];o $R(1,cD).3y([],q(2T,i){E(0==(i-b)%a&&(i-b)/a>=0)2T.1g(i);o 2T})},20:q(N,1K,1n,4n,6W){E(N.O==0)o[];E(1K==\'cv\')1K=\'2n+0\';E(1K==\'cw\')1K=\'2n+1\';G h=14.29,U=[],9D=[],m;h.7X(N);18(G i=0,L;L=N[i];i++){E(!L.1W.3V){h.1m(L.1W,4n,6W);9D.1g(L.1W)}}E(1K.1f(/^\\d+$/)){1K=55(1K);18(G i=0,L;L=N[i];i++)E(L.7Y==1K)U.1g(L)}1i E(m=1K.1f(/^(-?\\d*)?n(([+-])(\\d+))?/)){E(m[1]=="-")m[1]=-1;G a=m[1]?55(m[1]):1;G b=m[2]?55(m[2]):0;G 9E=14.2k.cC(a,b,N.O);18(G i=0,L,l=9E.O;L=N[i];i++){18(G j=0;j<l;j++)E(L.7Y==9E[j])U.1g(L)}}h.5q(N);h.5q(9D);o U},\'5F\':q(N,I,1n){18(G i=0,U=[],L;L=N[i];i++){E(L.15==\'!\'||L.5T)3P;U.1g(L)}o U},\'4Q\':q(N,42,1n){G h=14.29,gM,m;G 9F=1t 14(42).7V(1n);h.7X(9F);18(G i=0,U=[],L;L=N[i];i++)E(!L.3V)U.1g(L);h.5q(9F);o U},\'cu\':q(N,I,1n){18(G i=0,U=[],L;L=N[i];i++)E(!L.3G&&(!L.1r||L.1r!==\'5j\'))U.1g(L);o U},\'3G\':q(N,I,1n){18(G i=0,U=[],L;L=N[i];i++)E(L.3G)U.1g(L);o U},\'3T\':q(N,I,1n){18(G i=0,U=[],L;L=N[i];i++)E(L.3T)U.1g(L);o U}},6S:{\'=\':q(21,v){o 21==v},\'!=\':q(21,v){o 21!=v},\'^=\':q(21,v){o 21==v||21&&21.8s(v)},\'$=\':q(21,v){o 21==v||21&&21.8t(v)},\'*=\':q(21,v){o 21==v||21&&21.1H(v)},\'$=\':q(21,v){o 21.8t(v)},\'*=\':q(21,v){o 21.1H(v)},\'~=\':q(21,v){o(\' \'+21+\' \').1H(\' \'+v+\' \')},\'|=\':q(21,v){o(\'-\'+(21||"").2o()+\'-\').1H(\'-\'+(v||"").2o()+\'-\')}},4f:q(1u){G 4R=[];1u.ap(/(([\\w#:.~>+()\\s-]+|\\*|\\[.*?\\])+)\\s*(,|$)/,q(m){4R.1g(m[1].4i())});o 4R},cE:q(1Z,1u){G 2t=$$(1u),h=14.29;h.7X(2t);18(G i=0,U=[],k;k=1Z[i];i++)E(k.3V)U.1g(k);h.5q(2t);o U},5V:q(1Z,1u,1m){E(M.4Z(1u)){1m=1u;1u=1p}o 14.cE(1Z,1u||\'*\')[1m||0]},7z:q(k,4R){4R=14.4f(4R.2E(\',\'));G U=[],h=14.29;18(G i=0,l=4R.O,42;i<l;i++){42=1t 14(4R[i].4i());h.1V(U,42.7V(k))}o(l>1)?h.9x(U):U}});E(1e.1R.3W){M.17(14.29,{1V:q(a,b){18(G i=0,L;L=b[i];i++)E(L.15!=="!")a.1g(L);o a},5q:q(N){18(G i=0,L;L=N[i];i++)L.97(\'3V\');o N}})}q $$(){o 14.7z(1b,$A(1q))}G 1C={9G:q(1y){$(1y).9G();o 1y},cF:q(1Z,V){E(3i V!=\'W\')V={3z:!!V};1i E(M.2D(V.3z))V.3z=1v;G 1w,I,9H=1p,5r=V.5r;G 7f=1Z.3y({},q(1s,k){E(!k.3G&&k.1d){1w=k.1d;I=$(k).3f();E(I!=1j&&k.1r!=\'gN\'&&(k.1r!=\'5r\'||(!9H&&5r!==1p&&(!5r||1w==5r)&&(9H=1v)))){E(1w 1O 1s){E(!M.4D(1s[1w]))1s[1w]=[1s[1w]];1s[1w].1g(I)}1i 1s[1w]=I}}o 1s});o V.3z?7f:M.4C(7f)}};1C.1c={6Y:q(1y,V){o 1C.cF(1C.6c(1y),V)},6c:q(1y){o $A($(1y).4x(\'*\')).3y([],q(1Z,1J){E(1C.J.6d[1J.15.2b()])1Z.1g(J.17(1J));o 1Z})},gO:q(1y,7Z,1d){1y=$(1y);G 80=1y.4x(\'4y\');E(!7Z&&!1d)o $A(80).2S(J.17);18(G i=0,9I=[],O=80.O;i<O;i++){G 4y=80[i];E((7Z&&4y.1r!=7Z)||(1d&&4y.1d!=1d))3P;9I.1g(J.17(4y))}o 9I},9J:q(1y){1y=$(1y);1C.6c(1y).8A(\'9J\');o 1y},9K:q(1y){1y=$(1y);1C.6c(1y).8A(\'9K\');o 1y},cG:q(1y){G 1Z=$(1y).6c().5I(q(k){o\'5j\'!=k.1r&&!k.3G});G 9L=1Z.5I(q(k){o k.3S(\'7M\')&&k.7M>=0}).aM(q(k){o k.7M}).3M();o 9L?9L:1Z.8D(q(k){o[\'4y\',\'2G\',\'9M\'].1H(k.15.2b())})},gP:q(1y){1y=$(1y);1y.cG().cH();o 1y},2V:q(1y,V){1y=$(1y),V=M.2F(V||{});G 3a=V.3B,67=1y.5g(\'67\')||\'\';E(67.52())67=1D.7t.c2;V.3B=1y.6Y(1v);E(3a){E(M.3j(3a))3a=3a.7g();M.17(V.3B,3a)}E(1y.3S(\'1B\')&&!V.1B)V.1B=1y.1B;o 1t 1Q.58(67,V)}};1C.J={9N:q(k){$(k).9N();o k},2G:q(k){$(k).2G();o k}};1C.J.1c={6Y:q(k){k=$(k);E(!k.3G&&k.1d){G I=k.3f();E(I!=4A){G 1G={};1G[k.1d]=I;o M.4C(1G)}}o\'\'},3f:q(k){k=$(k);G 1B=k.15.2b();o 1C.J.6d[1B](k)},gQ:q(k,I){k=$(k);G 1B=k.15.2b();1C.J.6d[1B](k,I);o k},aQ:q(k){$(k).I=\'\';o k},gR:q(k){o $(k).I!=\'\'},cH:q(k){k=$(k);22{k.9N();E(k.2G&&(k.15.2b()!=\'4y\'||![\'9O\',\'9G\',\'5r\'].1H(k.1r)))k.2G()}26(e){}o k},9J:q(k){k=$(k);k.3G=1v;o k},9K:q(k){k=$(k);k.3G=1p;o k}};G gS=1C.J;G $F=1C.J.1c.3f;1C.J.6d={4y:q(k,I){4Y(k.1r.2b()){2g\'cI\':2g\'9P\':o 1C.J.6d.cJ(k,I);66:o 1C.J.6d.9M(k,I)}},cJ:q(k,I){E(M.2D(I))o k.3T?k.I:1j;1i k.3T=!!I},9M:q(k,I){E(M.2D(I))o k.I;1i k.I=I},2G:q(k,I){E(M.2D(I))o C[k.1r==\'2G-gT\'?\'cK\':\'cL\'](k);1i{G 3J,81,cM=!M.4D(I);18(G i=0,O=k.O;i<O;i++){3J=k.V[i];81=C.82(3J);E(cM){E(81==I){3J.9Q=1v;o}}1i 3J.9Q=I.1H(81)}}},cK:q(k){G 1m=k.gU;o 1m>=0?C.82(k.V[1m]):1j},cL:q(k){G 1S,O=k.O;E(!O)o 1j;18(G i=0,1S=[];i<O;i++){G 3J=k.V[i];E(3J.9Q)1S.1g(C.82(3J))}o 1S},82:q(3J){o J.17(3J).3S(\'I\')?3J.I:3J.4k}};4X.9R=2f.2u(ak,{2I:q($4c,k,4h,31){$4c(31,4h);C.k=$(k);C.4S=C.3f()},8g:q(){G I=C.3f();E(M.3j(C.4S)&&M.3j(I)?C.4S!=I:24(C.4S)!=24(I)){C.31(C.k,I);C.4S=I}}});1C.J.cN=2f.2u(4X.9R,{3f:q(){o 1C.J.3f(C.k)}});1C.cN=2f.2u(4X.9R,{3f:q(){o 1C.6Y(C.k)}});4X.6Z=2f.2u({2I:q(k,31){C.k=$(k);C.31=31;C.4S=C.3f();E(C.k.15.2b()==\'1y\')C.cO();1i C.6i(C.k)},9S:q(){G I=C.3f();E(C.4S!=I){C.31(C.k,I);C.4S=I}},cO:q(){1C.6c(C.k).1E(C.6i,C)},6i:q(k){E(k.1r){4Y(k.1r.2b()){2g\'cI\':2g\'9P\':1F.4T(k,\'cP\',C.9S.2B(C));2h;66:1F.4T(k,\'gV\',C.9S.2B(C));2h}}}});1C.J.6Z=2f.2u(4X.6Z,{3f:q(){o 1C.J.3f(C.k)}});1C.6Z=2f.2u(4X.6Z,{3f:q(){o 1C.6Y(C.k)}});E(!1D.1F)G 1F={};M.17(1F,{gW:8,gX:9,gY:13,gZ:27,h0:37,h1:38,h2:39,h3:40,h4:46,h5:36,h6:35,h7:33,h8:34,h9:45,2Y:{},9T:q(19){G k;4Y(19.1r){2g\'ha\':k=19.hb;2h;2g\'hc\':k=19.3F;2h;66:o 1j}o J.17(k)}});1F.1c=(q(){G 5s;E(1e.1R.3W){G cQ={0:1,1:4,2:2};5s=q(19,5t){o 19.9O==cQ[5t]}}1i E(1e.1R.4a){5s=q(19,5t){4Y(5t){2g 0:o 19.83==1&&!19.cR;2g 1:o 19.83==1&&19.cR;66:o 1p}}}1i{5s=q(19,5t){o 19.83?(19.83===5t+1):(19.9O===5t)}}o{hd:q(19){o 5s(19,0)},he:q(19){o 5s(19,1)},hf:q(19){o 5s(19,2)},k:q(19){19=1F.17(19);G L=19.84,1r=19.1r,5u=19.5u;E(5u&&5u.15){E(1r===\'cS\'||1r===\'cT\'||(1r===\'cP\'&&5u.15.2b()===\'4y\'&&5u.1r===\'9P\'))L=5u}E(L){E(L.3t==6A.bn)L=L.1W;o J.17(L)}1i o 1p},5V:q(19,1u){G k=1F.k(19);E(!1u)o k;G 1Z=[k].1V(k.5S());o 14.5V(1Z,1u,0)},5v:q(19){G 70=1b.5o,2c=1b.2c||{4v:0,4u:0};o{x:19.cU||(19.hg+(70.4v||2c.4v)-(70.hh||0)),y:19.cV||(19.hi+(70.4u||2c.4u)-(70.hj||0))}},hk:q(19){o 1F.5v(19).x},hl:q(19){o 1F.5v(19).y},8h:q(19){1F.17(19);19.cW();19.cX();19.hm=1v}}})();1F.17=(q(){G 2H=M.4b(1F.1c).3y({},q(m,1d){m[1d]=1F.1c[1d].4F();o m});E(1e.1R.3W){M.17(2H,{cX:q(){C.hn=1v},cW:q(){C.7c=1p},2C:q(){o"[W 1F]"}});o q(19){E(!19)o 1p;E(19.7R)o 19;19.7R=1e.3g;G 5v=1F.5v(19);M.17(19,{84:19.ho,9T:1F.9T(19),cU:5v.x,cV:5v.y});o M.17(19,2H)}}1i{1F.1k=1F.1k||1b.71("cY")[\'4U\'];M.17(1F.1k,2H);o 1e.K}})();M.17(1F,(q(){G 2Y=1F.2Y;q 9U(k){22{E(k.9V)o k.9V[0];1q.5A.1o=1q.5A.1o||1;o k.9V=[++1q.5A.1o]}26(cT){o 1p}}q 9W(1A){E(1A&&1A.1H(\':\'))o"cZ";o 1A}q 85(1o){o 2Y[1o]=2Y[1o]||{}}q 86(1o,1A){G c=85(1o);o c[1A]=c[1A]||[]}q d0(k,1A,2l){G 1o=9U(k);G c=86(1o,1A);E(c.5J("2l").1H(2l))o 1p;G 1L=q(19){E(!1F||!1F.17||(19.1A&&19.1A!=1A))o 1p;1F.17(19);2l.2L(k,19)};1L.2l=2l;c.1g(1L);o 1L}q 9X(1o,1A,2l){G c=86(1o,1A);o c.8D(q(1L){o 1L.2l==2l})}q d1(1o,1A,2l){G c=85(1o);E(!c[1A])o 1p;c[1A]=c[1A].6r(9X(1o,1A,2l))}q d2(){18(G 1o 1O 2Y)18(G 1A 1O 2Y[1o])2Y[1o][1A]=1j}E(1D.77){1D.77("c4",d2)}E(1e.1R.4a){1D.72(\'hp\',1e.3g,1p)}o{4T:q(k,1A,2l){k=$(k);G 1d=9W(1A);G 1L=d0(k,1A,2l);E(!1L)o k;E(k.72){k.72(1d,1L,1p)}1i{k.77("5O"+1d,1L)}o k},5w:q(k,1A,2l){k=$(k);G 1o=9U(k),1d=9W(1A);E(!2l&&1A){86(1o,1A).1E(q(1L){k.5w(1A,1L.2l)});o k}1i E(!1A){M.4b(85(1o)).1E(q(1A){k.5w(1A)});o k}G 1L=9X(1o,1A,2l);E(!1L)o k;E(k.d3){k.d3(1d,1L,1p)}1i{k.hq("5O"+1d,1L)}d1(1o,1A,2l);o k},6e:q(k,1A,2T){k=$(k);E(k==1b&&1b.71&&!k.d4)k=1b.5o;G 19;E(1b.71){19=1b.71("cY");19.hr("cZ",1v,1v)}1i{19=1b.hs();19.d5="ht"}19.1A=1A;19.2T=2T||{};E(1b.71){k.d4(19)}1i{k.hu(19.d5,19)}o 1F.17(19)}}})());M.17(1F,1F.1c);J.6h({6e:1F.6e,4T:1F.4T,5w:1F.5w});M.17(1b,{6e:J.1c.6e.4F(),4T:J.1c.4T.4F(),5w:J.1c.5w.4F(),73:1p});(q(){G 41;q 74(){E(1b.73)o;E(41)1D.am(41);1b.6e("hv:73");1b.73=1v}E(1b.72){E(1e.1R.4a){41=1D.al(q(){E(/73|d6/.2R(1b.2X))74()},0);1F.4T(1D,"cS",74)}1i{1b.72("hw",74,1p)}}1i{1b.6H("<4V 1o=d7 4E c3=//:><\\/4V>");$("d7").7o=q(){E(C.2X=="d6"){C.7o=1j;74()}}}})();3Y.4C=M.4C;G hx={3E:J.bo};J.1c.hy=J.1c.7E;G hz={hA:q(k,1a){o J.3D(k,{53:1a})},hB:q(k,1a){o J.3D(k,{2q:1a})},hC:q(k,1a){o J.3D(k,{5e:1a})},hD:q(k,1a){o J.3D(k,{7w:1a})}};G $3P=1t hE(\'"4B $3P" hF hG, hH "o" hI\');G 9Y={d8:1p,9Z:q(){C.d9=1D.cj||1b.5o.4v||1b.2c.4v||0;C.da=1D.ck||1b.5o.4u||1b.2c.4u||0},hJ:q(k,x,y){E(C.d8)o C.db(k,x,y);C.75=x;C.76=y;C.3d=J.4s(k);o(y>=C.3d[1]&&y<C.3d[1]+k.61&&x>=C.3d[0]&&x<C.3d[0]+k.60)},db:q(k,x,y){G a0=J.9j(k);C.75=x+a0[0]-C.d9;C.76=y+a0[1]-C.da;C.3d=J.4s(k);o(C.76>=C.3d[1]&&C.76<C.3d[1]+k.61&&C.75>=C.3d[0]&&C.75<C.3d[0]+k.60)},hK:q(4N,k){E(!4N)o 0;E(4N==\'hL\')o((C.3d[1]+k.61)-C.76)/k.61;E(4N==\'hM\')o((C.3d[0]+k.60)-C.75)/k.60},4s:J.1c.4s,6L:J.1c.6L,9g:q(k){9Y.9Z();o J.9g(k)},9i:q(k){9Y.9Z();o J.9i(k)},hN:J.1c.9j,2O:J.1c.64,hO:J.1c.6M,2F:q(25,84,V){V=V||{};o J.bR(84,25,V)}};E(!1b.87)1b.87=q(dc){q a1(1d){o 1d.52()?1j:"[5h(1V(\' \', @6D, \' \'), \' "+1d+" \')]"}dc.87=1e.3K.79?q(k,1l){1l=1l.2J().4i();G a2=/\\s/.2R(1l)?$w(1l).2S(a1).2E(\'\'):a1(1l);o a2?1b.90(\'.//*\'+a2,k):[]}:q(k,1l){1l=1l.2J().4i();G 1Z=[],6I=(/\\s/.2R(1l)?$w(1l):1j);E(!6I&&!1l)o 1Z;G N=$(k).4x(\'*\');1l=\' \'+1l+\' \';18(G i=0,1J,cn;1J=N[i];i++){E(1J.1l&&(cn=\' \'+1J.1l+\' \')&&(cn.1H(1l)||(6I&&6I.8y(q(1d){o!1d.2J().52()&&cn.1H(\' \'+1d+\' \')}))))1Z.1g(J.17(1J))}o 1Z};o q(1l,7u){o $(7u||1b.2c).87(1l)}}(J.1c);J.7B=2f.2u();J.7B.1k={2I:q(k){C.k=$(k)},4m:q(1h){C.k.1l.4f(/\\s+/).2G(q(1d){o 1d.O>0}).4m(1h)},6t:q(1l){C.k.1l=1l},hP:q(a3){E(C.1H(a3))o;C.6t($A(C).1V(a3).2E(\' \'))},br:q(a4){E(!C.1H(a4))o;C.6t($A(C).6r(a4).2E(\' \'))},2J:q(){o $A(C).2E(\' \')}};M.17(J.7B.1k,2K);J.6h();',62,1106,'||||||||||||||||||||element||||return||function||||||||||||this||if||var||value|Element||node|Object|nodes|length||||||results|options|object||style||||||Selector|tagName||extend|for|event|content|document|Methods|name|Prototype|match|push|iterator|else|null|prototype|className|index|root|id|false|arguments|type|result|new|expression|true|key|position|form|property|eventName|method|Form|window|each|Event|pair|include|context|child|formula|wrapper|klass|div|in|while|Ajax|Browser|values|replace|args|concat|parentNode|attribute|transport|elements|nth|nv|try||String|source|catch||pattern|handlers|combinator|toLowerCase|body|attr|getStyle|Class|case|break|filter|width|pseudos|handler|Array||toUpperCase|attributes|top|_getEv|xpath|matches|create|array|left|last|response|of|isFunction|bind|inspect|isUndefined|join|clone|select|methods|initialize|toString|Enumerable|call|valueT|valueL|offsetParent|evaluate|parent|test|map|memo|iterable|request|url|readyState|cache|proceed||callback|Template||||||||params|responseText|height|offset|targetNode|getValue|emptyFunction|properties|typeof|isString|string|__method|gsub|childNodes|json|px|indexOf|apply|toJSON|nodeType|names|replacement|slice|count|inject|hash|toArray|parameters|container|insert|display|toElement|disabled|ByTag|le|opt|BrowserFeatures|ancestor|first|onComplete|insertions|continue|_attributeTranslations|opacity|hasAttribute|checked|matcher|_countedByPrototype|IE|createElement|Hash|number||timer|selector|els|mm|||navigator|userAgent|Opera|WebKit|keys|super|isElement|toHTML|split|RegExp|frequency|strip|stripScripts|text|nodeValue|_each|reverse|_object|start|responder|nextSibling|cumulativeOffset|_returnOffset|scrollTop|scrollLeft|ps|getElementsByTagName|input|wrap|undefined|throw|toQueryString|isArray|defer|methodize|toPaddedString|parts|status|nextSiblings|styles|tags|table|mode|descendant|sibling|not|expressions|lastValue|observe|__proto__|script|shift|Abstract|switch|isNumber|evalScripts|innerHTML|blank|before|item|Number|update|end|Request|dispatchException|headers|success|insertion|decay|bottom|adjacent|readAttribute|contains|parseFloat|hidden|_overflow|offsetTop|offsetLeft|currentStyle|documentElement|_cache|unmark|submit|isButton|code|currentTarget|pointer|stopObserving|destination|interpret|str|callee|truncation|self|substring|evalJSON|empty|template|appendChild|findAll|pluck|right|exclusive|Responders|extras|on|getHeader|receiver|_insertionTranslations|ancestors|firstChild|previousSiblings|findElement|getDimensions|pos|setStyle|setOpacity|offsetWidth|offsetHeight|absolute|static|getOffsetParent|delta|default|action|tbody|Heading|attrPresence|fragment|getElements|Serializers|fire|ElementExtensions|HTMLElement|addMethods|registerCallback|onTimerEvent|escapeHTML|capitalize|_|ctx|expr|fillWith|criteria|without|toObject|set|responders|post|contentType|xml|getStatus|state|Node|writeAttribute|removeChild|class|previousElementSibling|next|nextElementSibling|write|classNames|auto|relative|positionedOffset|viewportOffset|_flag|dimensions|patterns|following|laterSibling|operators|pseudo|only|and|ofType|nodeClassName|serialize|EventObserver|docElement|createEvent|addEventListener|loaded|fireContentLoadedEvent|xcomp|ycomp|attachEvent|Gecko|XPath|SpecificElementExtensions|ScriptFragment|returnValue|currentlyExecuting|eval|data|toQueryParams|times|charAt|detect|dispatch|onCreate|asynchronous|application|onreadystatechange|html|headerJSON|isSameOrigin|port|location|parentElement|none|after|_getContentFromAnonymousElement|recursivelyCollect|findChildElements|read|ClassNames|hasClassName|elementClassName|descendantOf|cssFloat|00001|dim|border|padding|title|_getAttr|tabIndex|insertBefore|TBODY|tr|Simulated|_extendedByPrototype|refresh|copy|onlyIfAbsent|findElements|token|mark|nodeIndex|typeName|inputs|currentValue|optionValue|which|target|getCacheForID|getWrappersForEventName|getElementsByClassName|Version|superclass|subclass|valueOf|isHash|curry|delay|_methodized|execute|stop|prepareReplacement|stripTags|decodeURIComponent|succ|camelize|len|camelized|escapedString|character|unfilterJSON|startsWith|endsWith|lastIndexOf|toTemplateReplacements|slices|collect|all|found|invoke|trues|falses|find|_reverse|toQueryPair|get|delete|activeRequestCount|Base|encoding|evalJS|_complete|Response|respondToReadyState|onStateChange|Content|Complete|protocol|domain|getResponseHeader|exception|statusText|getAllResponseHeaders|failure|updater|_getElementsByXPath|query|visible|range|replaceChild|identify|getAttribute|removeAttribute|float|css|elementStyle|cssText|styleFloat|visibility|_madePositioned|overflow|absolutize|offsets|relativize|cumulativeScrollOffset|forElement|val|zoom|alpha|stripAlpha|has|fragments|TD|trans|TableSection|HTML|tag|_div|unique|tokens|assertions|preceding|exclusion|predicate|indexed|indices|exclusions|reset|submitted|matchingInputs|disable|enable|firstByIndex|textarea|focus|button|radio|selected|TimedObserver|onElementEvent|relatedTarget|getEventID|_prototypeEventID|getDOMEventName|findWrapper|Position|prepare|offsetcache|iter|cond|classNameToAdd|classNameToRemove|KHTML|MobileSafari|Safari|SelectorsAPI|querySelector|JSONFilter|subclasses|argumentNames|instanceof|timeout|1000|Try|these|lambda|escape|PeriodicalExecuter|setInterval|clearInterval|specialChar|sub|scan|img|extractScripts||matchAll|matchOne|scriptTag|unescapeHTML|separator|charCodeAt|useDoubleQuotes|isJSON|sanitize|JSON|interpolate|amp|lt|createTextNode|Pattern|exec|comp|eachSlice|any|sortBy|collections|size|from|clear|flatten|inline|uniq|sorted|forEach|arrayLength|radix|encodeURIComponent|ObjectRange|getTransport|XMLHttpRequest|ActiveXObject|XMLHTTP|register|setRequestHeaders|overrideMimeType|2005|requestHeaders|Events|force|evalResponse|onException|getStatusText|_getHeaderJSON|responseXML|_getResponseJSON|sanitizeJSON|Updater|updateContent|updateComplete|lastText|ELEMENT_NODE|TEXT_NODE|toggle|hide|show|remove|descendants|firstDescendant|immediateDescendants|previousSibling|counter|setAttribute|getHeight|getWidth|addClassName|removeClassName|nextNode|compareDocumentPosition|scrollTo|originalVisibility|originalPosition|originalDisplay|originalWidth|clientWidth|originalHeight|clientHeight|BODY|_originalLeft|_originalTop|_originalWidth|_originalHeight|clonePosition|setLeft|setTop|setWidth|setHeight|htmlFor|parseInt|100|normal|_getAttrNode|getAttributeNode|href|src|onunload|IMG|outerHTML|TR|td|SELECT|THEAD|TFOOT|TH|TEXTAREA|findDOMClass|Mod|TableCol|TableCell|client|pageXOffset|pageYOffset|shouldUseSelectorsAPI|selectorsAPI||shouldUseXPath|compileXPathMatcher|compileMatcher|oldId|local|or|enabled|even|odd|_true|uTagName|byClassName|needle|operator|getIndices|total|matchElements|serializeElements|findFirstElement|activate|checkbox|inputSelector|selectOne|selectMany|single|Observer|registerFormCallbacks|click|buttonMap|metaKey|load|error|pageX|pageY|preventDefault|stopPropagation|HTMLEvents|dataavailable|createWrapper|destroyWrapper|destroyCache|removeEventListener|dispatchEvent|eventType|complete|__onDOMContentLoaded|includeScrollOffsets|deltaX|deltaY|withinIncludingScrolloffsets|instanceMethods|AppleWebKit|Apple|Mobile|secure|constructor|RangeError|unknown|boolean|splice|Function|bindAsEventListener||setTimeout|01|Date|getUTCFullYear|getUTCMonth|getUTCDate|getUTCHours|getUTCMinutes|getUTCSeconds|finally|truncate|im|fromCharCode|underscore|dasherize|x00|x1f|u00|Eaeflnr|SyntaxError|Badly|formed|parseQuery|grep|inGroupsOf|max|min|partition|reject|sort|zip|pop|member|entries|every|some|compact|reduce|intersect|isNaN|toColorPart|isFinite|abs|round|ceil|floor|Math|unset|merge|Msxml2|Microsoft|unregister|www|urlencoded|UTF|_method|Konqueror|open|postBody|send||Requested|With|Accept|javascript|charset|Connection|close|setRequestHeader|200|300|Success|Failure|java|ecma|https|Uninitialized|Loading|Loaded|Interactive|responseJSON|getAllHeaders|PeriodicalUpdater|clearTimeout|getElementById|XPathResult|ORDERED_NODE_SNAPSHOT_TYPE|snapshotLength|snapshotItem|ATTRIBUTE_NODE|CDATA_SECTION_NODE|ENTITY_REFERENCE_NODE|ENTITY_NODE|PROCESSING_INSTRUCTION_NODE|COMMENT_NODE|DOCUMENT_NODE|DOCUMENT_TYPE_NODE|DOCUMENT_FRAGMENT_NODE|NOTATION_NODE|cloneNode|ownerDocument|createRange|selectNode|createContextualFragment|siblings|up|down|previous|anonymous_element_|toggleClassName|cleanWhitespace|defaultView|getComputedStyle|getOpacity|block|makePositioned|undoPositioned|makeClipping|undoClipping|getElementsBySelector|childElements|fixed|hasLayout|cellpadding|cellPadding|cellspacing|cellSpacing|colSpan|rowSpan|vAlign|dateTime|accessKey|encType|maxLength|readOnly|longDesc|frameBorder|readonly|multiple|onload|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onfocus|onblur|onkeypress|onkeydown|onkeyup|onsubmit|onreset|onselect|onchange|rv|999999|TABLE|specified|FORM|INPUT|OPTGROUP|OptGroup|TextArea|Paragraph|FIELDSET|FieldSet|UL|UList|OL|OList|DL|DList|DIR|Directory|H1|H2|H3||H4|H5|H6|Quote|INS|DEL|Anchor|Image|CAPTION|TableCaption||COL|COLGROUP|TableRow|FRAMESET|FrameSet|IFRAME|IFrame|viewport|inner|opera|version|getScrollOffsets|querySelectorAll|starts|with|mod|dis|abled|selectorType|file|getInputs|focusFirstElement|setValue|present|Field|one|selectedIndex|change|KEY_BACKSPACE|KEY_TAB|KEY_RETURN|KEY_ESC|KEY_LEFT|KEY_UP|KEY_RIGHT|KEY_DOWN|KEY_DELETE|KEY_HOME|KEY_END|KEY_PAGEUP|KEY_PAGEDOWN|KEY_INSERT|mouseover|fromElement|mouseout|isLeftClick|isMiddleClick|isRightClick|clientX|clientLeft|clientY|clientTop|pointerX|pointerY|stopped|cancelBubble|srcElement|unload|detachEvent|initEvent|createEventObject|ondataavailable|fireEvent|dom|DOMContentLoaded|Toggle|childOf|Insertion|Before|Top|Bottom|After|Error|is|deprecated|use|instead|within|overlap|vertical|horizontal|realOffset|page|add'.split('|'),0,{}));

/*
* Really easy field validation with Prototype
* http://tetlaw.id.au/view/javascript/really-easy-field-validation
* Andrew Tetlaw
* Version 1.5.4.1 (2007-01-05)
*
* Copyright (c) 2007 Andrew Tetlaw
* 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.
*
*/
var Validator = Class.create();

Validator.prototype = {
 initialize : function(className, error, test, options) {
 if(typeof test == 'function'){
 this.options = $H(options);
 this._test = test;
 } else {
 this.options = $H(test);
 this._test = function(){return true};
 }
 this.error = error || 'Validation failed.';
 this.className = className;
 },
 test : function(v, elm) {
 return (this._test(v,elm) && this.options.all(function(p){
 return Validator.methods[p.key] ? Validator.methods[p.key](v,elm,p.value) : true;
 }));
 }
}
Validator.methods = {
 pattern : function(v,elm,opt) {return Validation.get('IsEmpty').test(v) || opt.test(v)},
 minLength : function(v,elm,opt) {return v.length >= opt},
 maxLength : function(v,elm,opt) {return v.length <= opt},
 min : function(v,elm,opt) {return v >= parseFloat(opt)},
 max : function(v,elm,opt) {return v <= parseFloat(opt)},
 notOneOf : function(v,elm,opt) {return $A(opt).all(function(value) {
 return v != value;
 })},
 oneOf : function(v,elm,opt) {return $A(opt).any(function(value) {
 return v == value;
 })},
 is : function(v,elm,opt) {return v == opt},
 isNot : function(v,elm,opt) {return v != opt},
 equalToField : function(v,elm,opt) {return v == $F(opt)},
 notEqualToField : function(v,elm,opt) {return v != $F(opt)},
 include : function(v,elm,opt) {return $A(opt).all(function(value) {
 return Validation.get(value).test(v,elm);
 })}
}

var Validation = Class.create();
Validation.defaultOptions = {
 onSubmit : true,
 stopOnFirst : false,
 immediate : false,
 focusOnError : true,
 useTitles : false,
 addClassNameToContainer: false,
 containerClassName: '.input-box',
 onFormValidate : function(result, form) {},
 onElementValidate : function(result, elm) {}
};

Validation.prototype = {
 initialize : function(form, options){
 this.form = $(form);
 if (!this.form) {
 return;
 }
 this.options = Object.extend({
 onSubmit : Validation.defaultOptions.onSubmit,
 stopOnFirst : Validation.defaultOptions.stopOnFirst,
 immediate : Validation.defaultOptions.immediate,
 focusOnError : Validation.defaultOptions.focusOnError,
 useTitles : Validation.defaultOptions.useTitles,
 onFormValidate : Validation.defaultOptions.onFormValidate,
 onElementValidate : Validation.defaultOptions.onElementValidate
 }, options || {});
 if(this.options.onSubmit) Event.observe(this.form,'submit',this.onSubmit.bind(this),false);
 if(this.options.immediate) {
 Form.getElements(this.form).each(function(input) { // Thanks Mike! 
 if (input.tagName.toLowerCase() == 'select') {
 Event.observe(input, 'blur', this.onChange.bindAsEventListener(this));
 }
 Event.observe(input, 'change', this.onChange.bindAsEventListener(this));
 }, this);
 }
 },
 onChange : function (ev) {
 Validation.isOnChange = true;
 Validation.validate(Event.element(ev),{
 useTitle : this.options.useTitles, 
 onElementValidate : this.options.onElementValidate
 });
 Validation.isOnChange = false; 
 },
 onSubmit : function(ev){
 if(!this.validate()) Event.stop(ev);
 },
 validate : function() {
 var result = false;
 var useTitles = this.options.useTitles;
 var callback = this.options.onElementValidate;
 try {
 if(this.options.stopOnFirst) {
 result = Form.getElements(this.form).all(function(elm) { return Validation.validate(elm,{useTitle : useTitles, onElementValidate : callback}); });
 } else {
 result = Form.getElements(this.form).collect(function(elm) { return Validation.validate(elm,{useTitle : useTitles, onElementValidate : callback}); }).all();
 }
 } catch (e) {

 }
 if(!result && this.options.focusOnError) {
 try{
 Form.getElements(this.form).findAll(function(elm){return $(elm).hasClassName('validation-failed')}).first().focus()
 }
 catch(e){

 }
 }
 this.options.onFormValidate(result, this.form);
 return result;
 },
 reset : function() {
 Form.getElements(this.form).each(Validation.reset);
 }
}

Object.extend(Validation, {
 validate : function(elm, options){
 options = Object.extend({
 useTitle : false,
 onElementValidate : function(result, elm) {}
 }, options || {});
 elm = $(elm);

 var cn = $w(elm.className);
 return result = cn.all(function(value) {
 var test = Validation.test(value,elm,options.useTitle);
 options.onElementValidate(test, elm);
 return test;
 });
 },
 insertAdvice : function(elm, advice){
 var container = $(elm).up('.field-row');
 if(container){
 Element.insert(container, {after: advice});
 } else if (elm.up('td.value')) {
 elm.up('td.value').insert({bottom: advice});
 } else if (elm.advaiceContainer && $(elm.advaiceContainer)) {
 $(elm.advaiceContainer).update(advice);
 }
 else {
 switch (elm.type.toLowerCase()) {
 case 'checkbox':
 case 'radio':
 var p = elm.parentNode;
 if(p) {
 Element.insert(p, {'bottom': advice});
 } else {
 Element.insert(elm, {'after': advice});
 }
 break;
 default:
 Element.insert(elm, {'after': advice});
 }
 }
 },
 showAdvice : function(elm, advice, adviceName){
 if(!elm.advices){
 elm.advices = new Hash();
 }
 else{
 elm.advices.each(function(pair){
 this.hideAdvice(elm, pair.value);
 }.bind(this));
 }
 elm.advices.set(adviceName, advice);
 if(typeof Effect == 'undefined') {
 advice.style.display = 'block';
 } else {
 if(!advice._adviceAbsolutize) {
 new Effect.Appear(advice, {duration : 1 });
 } else {
 Position.absolutize(advice);
 advice.show();
 advice.setStyle({
 'top':advice._adviceTop,
 'left': advice._adviceLeft,
 'width': advice._adviceWidth,
 'z-index': 1000
 });
 advice.addClassName('advice-absolute');
 }
 }
 },
 hideAdvice : function(elm, advice){
 if(advice != null) advice.hide();
 },
 updateCallback : function(elm, status) {
 if (typeof elm.callbackFunction != 'undefined') {
 eval(elm.callbackFunction+'(\''+elm.id+'\',\''+status+'\')');
 }
 },
 ajaxError : function(elm, errorMsg) {
 var name = 'validate-ajax';
 var advice = Validation.getAdvice(name, elm);
 if (advice == null) {
 advice = this.createAdvice(name, elm, false, errorMsg);
 }
 this.showAdvice(elm, advice, 'validate-ajax');
 this.updateCallback(elm, 'failed');

 elm.addClassName('validation-failed');
 elm.addClassName('validate-ajax');
 if (Validation.defaultOptions.addClassNameToContainer && Validation.defaultOptions.containerClassName != '') {
 var container = elm.up(Validation.defaultOptions.containerClassName);
 if (container && this.allowContainerClassName(elm)) {
 container.removeClassName('validation-passed');
 container.addClassName('validation-error');
 }
 }
 },
 allowContainerClassName: function (elm) {
 if (elm.type == 'radio' || elm.type == 'checkbox') {
 return elm.hasClassName('change-container-classname');
 }
 
 return true;
 },
 test : function(name, elm, useTitle) {
 var v = Validation.get(name);
 var prop = '__advice'+name.camelize();
 try {
 if(Validation.isVisible(elm) && !v.test($F(elm), elm)) {
 //if(!elm[prop]) {
 var advice = Validation.getAdvice(name, elm);
 if (advice == null) {
 advice = this.createAdvice(name, elm, useTitle);
 }
 this.showAdvice(elm, advice, name);
 this.updateCallback(elm, 'failed');
 //}
 elm[prop] = 1;
 if (!elm.advaiceContainer) {
 elm.removeClassName('validation-passed');
 elm.addClassName('validation-failed');
 } 
 
 if (Validation.defaultOptions.addClassNameToContainer && Validation.defaultOptions.containerClassName != '') {
 var container = elm.up(Validation.defaultOptions.containerClassName);
 if (container && this.allowContainerClassName(elm)) {
 container.removeClassName('validation-passed');
 container.addClassName('validation-error');
 }
 }
 return false;
 } else {
 var advice = Validation.getAdvice(name, elm);
 this.hideAdvice(elm, advice);
 this.updateCallback(elm, 'passed');
 elm[prop] = '';
 elm.removeClassName('validation-failed');
 elm.addClassName('validation-passed');
 if (Validation.defaultOptions.addClassNameToContainer && Validation.defaultOptions.containerClassName != '') {
 var container = elm.up(Validation.defaultOptions.containerClassName);
 if (container && !container.down('.validation-failed') && this.allowContainerClassName(elm)) {
 if (!Validation.get('IsEmpty').test(elm.value) || !this.isVisible(elm)) { 
 container.addClassName('validation-passed');
 } else {
 container.removeClassName('validation-passed');
 }
 container.removeClassName('validation-error');
 }
 }
 return true;
 }
 } catch(e) {
 throw(e)
 }
 },
 isVisible : function(elm) {
 while(elm.tagName != 'BODY') {
 if(!$(elm).visible()) return false;
 elm = elm.parentNode;
 }
 return true;
 },
 getAdvice : function(name, elm) {
 return $('advice-' + name + '-' + Validation.getElmID(elm)) || $('advice-' + Validation.getElmID(elm));
 },
 createAdvice : function(name, elm, useTitle, customError) {
 var v = Validation.get(name);
 var errorMsg = useTitle ? ((elm && elm.title) ? elm.title : v.error) : v.error;
 if (customError) {
 errorMsg = customError;
 }
 try {
 if (Translator){
 errorMsg = Translator.translate(errorMsg);
 }
 }
 catch(e){}

 advice = '<div class="validation-advice" id="advice-' + name + '-' + Validation.getElmID(elm) +'" style="display:none">' + errorMsg + '</div>'


 Validation.insertAdvice(elm, advice);
 advice = Validation.getAdvice(name, elm);
 if($(elm).hasClassName('absolute-advice')) {
 var dimensions = $(elm).getDimensions();
 var originalPosition = Position.cumulativeOffset(elm);

 advice._adviceTop = (originalPosition[1] + dimensions.height) + 'px';
 advice._adviceLeft = (originalPosition[0]) + 'px';
 advice._adviceWidth = (dimensions.width) + 'px';
 advice._adviceAbsolutize = true;
 }
 return advice;
 },
 getElmID : function(elm) {
 return elm.id ? elm.id : elm.name;
 },
 reset : function(elm) {
 elm = $(elm);
 var cn = $w(elm.className);
 cn.each(function(value) {
 var prop = '__advice'+value.camelize();
 if(elm[prop]) {
 var advice = Validation.getAdvice(value, elm);
 if (advice) {
 advice.hide();
 }
 elm[prop] = '';
 }
 elm.removeClassName('validation-failed');
 elm.removeClassName('validation-passed');
 if (Validation.defaultOptions.addClassNameToContainer && Validation.defaultOptions.containerClassName != '') {
 var container = elm.up(Validation.defaultOptions.containerClassName);
 if (container) {
 container.removeClassName('validation-passed');
 container.removeClassName('validation-error');
 }
 }
 });
 },
 add : function(className, error, test, options) {
 var nv = {};
 nv[className] = new Validator(className, error, test, options);
 Object.extend(Validation.methods, nv);
 },
 addAllThese : function(validators) {
 var nv = {};
 $A(validators).each(function(value) {
 nv[value[0]] = new Validator(value[0], value[1], value[2], (value.length > 3 ? value[3] : {}));
 });
 Object.extend(Validation.methods, nv);
 },
 get : function(name) {
 return Validation.methods[name] ? Validation.methods[name] : Validation.methods['_LikeNoIDIEverSaw_'];
 },
 methods : {
 '_LikeNoIDIEverSaw_' : new Validator('_LikeNoIDIEverSaw_','',{})
 }
});

Validation.add('IsEmpty', '', function(v) {
 return (v == '' || (v == null) || (v.length == 0) || /^\s+$/.test(v)); // || /^\s+$/.test(v));
});

Validation.addAllThese([
 ['validate-select', 'Please select an option.', function(v) {
 return ((v != "none") && (v != null) && (v.length != 0));
 }],
 ['required-entry', 'This is a required field.', function(v) {
 return !Validation.get('IsEmpty').test(v);
 }],
 ['validate-number', 'Please enter a valid number in this field.', function(v) {
 return Validation.get('IsEmpty').test(v) || (!isNaN(parseNumber(v)) && !/^\s+$/.test(parseNumber(v)));
 }],
 ['validate-digits', 'Please use numbers only in this field. please avoid spaces or other characters such as dots or commas.', function(v) {
 return Validation.get('IsEmpty').test(v) || !/[^\d]/.test(v);
 }],
 ['validate-alpha', 'Please use letters only (a-z or A-Z) in this field.', function (v) {
 return Validation.get('IsEmpty').test(v) || /^[a-zA-Z]+$/.test(v)
 }],
 ['validate-code', 'Please use only letters (a-z), numbers (0-9) or underscore(_) in this field, first character should be a letter.', function (v) {
 return Validation.get('IsEmpty').test(v) || /^[a-z]+[a-z0-9_]+$/.test(v)
 }],
 ['validate-alphanum', 'Please use only letters (a-z or A-Z) or numbers (0-9) only in this field. No spaces or other characters are allowed.', function(v) {
 return Validation.get('IsEmpty').test(v) || /^[a-zA-Z0-9]+$/.test(v) /*!/\W/.test(v)*/
 }],
 ['validate-street', 'Please use only letters (a-z or A-Z) or numbers (0-9) or spaces and # only in this field.', function(v) {
 return Validation.get('IsEmpty').test(v) || /^[ \w]{3,}([A-Za-z]\.)?([ \w]*\#\d+)?(\r\n| )[ \w]{3,}/.test(v)
 }],
 ['validate-phoneStrict', 'Please enter a valid phone number. For example (123) 456-7890 or 123-456-7890.', function(v) {
 return Validation.get('IsEmpty').test(v) || /^(\()?\d{3}(\))?(-|\s)?\d{3}(-|\s)\d{4}$/.test(v);
 }],
 ['validate-phoneLax', 'Please enter a valid phone number. For example (123) 456-7890 or 123-456-7890.', function(v) {
 return Validation.get('IsEmpty').test(v) || /^((\d[-. ]?)?((\(\d{3}\))|\d{3}))?[-. ]?\d{3}[-. ]?\d{4}$/.test(v);
 }],
 ['validate-fax', 'Please enter a valid fax number. For example (123) 456-7890 or 123-456-7890.', function(v) {
 return Validation.get('IsEmpty').test(v) || /^(\()?\d{3}(\))?(-|\s)?\d{3}(-|\s)\d{4}$/.test(v);
 }],
 ['validate-date', 'Please enter a valid date.', function(v) {
 var test = new Date(v);
 return Validation.get('IsEmpty').test(v) || !isNaN(test);
 }],
 ['validate-email', 'Please enter a valid email address. For example johndoe@domain.com.', function (v) {
 //return Validation.get('IsEmpty').test(v) || /\w{1,}[@][\w\-]{1,}([.]([\w\-]{1,})){1,3}$/.test(v)
 //return Validation.get('IsEmpty').test(v) || /^[\!\#$%\*/?|\^\{\}`~&\'\+\-=_a-z0-9][\!\#$%\*/?|\^\{\}`~&\'\+\-=_a-z0-9\.]{1,30}[\!\#$%\*/?|\^\{\}`~&\'\+\-=_a-z0-9]@([a-z0-9_-]{1,30}\.){1,5}[a-z]{2,4}$/i.test(v)
 return Validation.get('IsEmpty').test(v) || /^[a-z0-9,!\#\$%&'\*\+/=\?\^_`\{\|}~-]+(\.[a-z0-9,!#\$%&'\*\+/=\?\^_`\{\|}~-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*\.([a-z]{2,})/i.test(v)
 }],
 ['validate-emailSender', 'Please use only letters (a-z or A-Z), numbers (0-9) , underscore(_) or spaces in this field.', function (v) {
 return Validation.get('IsEmpty').test(v) || /^[a-zA-Z0-9_\s]+$/.test(v)
 }],
 ['validate-password', 'Please enter 6 or more characters. Leading or trailing spaces will be ignored.', function(v) {
 var pass=v.strip(); /*strip leading and trailing spaces*/
 return !(pass.length>0 && pass.length < 6);
 }],
 ['validate-admin-password', 'Please enter 7 or more characters. Password should contain both numeric and alphabetic characters.', function(v) {
 var pass=v.strip();
 if (0 == pass.length) {
 return true;
 }
 if (!(/[a-z]/i.test(v)) || !(/[0-9]/.test(v))) {
 return false;
 }
 return !(pass.length < 7);
 }],
 ['validate-cpassword', 'Please make sure your passwords match.', function(v) {
 if ($('password')) {
 var pass = $('password');
 }
 else {
 var pass = $$('.validate-password').length ? $$('.validate-password')[0] : $$('.validate-admin-password')[0];
 }
 var conf = $('confirmation') ? $('confirmation') : $$('.validate-cpassword')[0];
 return (pass.value == conf.value);
 }],
 ['validate-url', 'Please enter a valid URL. http:// is required', function (v) {
 return Validation.get('IsEmpty').test(v) || /^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?\/?/i.test(v)
 }],
 ['validate-clean-url', 'Please enter a valid URL. For example http://www.example.com or www.example.com', function (v) {
 return Validation.get('IsEmpty').test(v) || /^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+.(com|org|net|dk|at|us|tv|info|uk|co.uk|biz|se)$)(:(\d+))?\/?/i.test(v) || /^(www)((\.[A-Z0-9][A-Z0-9_-]*)+.(com|org|net|dk|at|us|tv|info|uk|co.uk|biz|se)$)(:(\d+))?\/?/i.test(v)
 }],
 ['validate-identifier', 'Please enter a valid Identifier. For example example-page, example-page.html or anotherlevel/example-page', function (v) {
 return Validation.get('IsEmpty').test(v) || /^[A-Z0-9][A-Z0-9_\/-]+(\.[A-Z0-9_-]+)*$/i.test(v)
 }],
 ['validate-xml-identifier', 'Please enter a valid XML-identifier. For example something_1, block5, id-4', function (v) {
 return Validation.get('IsEmpty').test(v) || /^[A-Z][A-Z0-9_\/-]*$/i.test(v)
 }],
 ['validate-ssn', 'Please enter a valid social security number. For example 123-45-6789.', function(v) {
 return Validation.get('IsEmpty').test(v) || /^\d{3}-?\d{2}-?\d{4}$/.test(v);
 }],
 ['validate-zip', 'Please enter a valid zip code. For example 90602 or 90602-1234.', function(v) {
 return Validation.get('IsEmpty').test(v) || /(^\d{5}$)|(^\d{5}-\d{4}$)/.test(v);
 }],
 ['validate-zip-international', 'Please enter a valid zip code.', function(v) {
 //return Validation.get('IsEmpty').test(v) || /(^[A-z0-9]{2,10}([\s]{0,1}|[\-]{0,1})[A-z0-9]{2,10}$)/.test(v);
 return true;
 }],
 ['validate-date-au', 'Please use this date format: dd/mm/yyyy. For example 17/03/2006 for the 17th of March, 2006.', function(v) {
 if(Validation.get('IsEmpty').test(v)) return true;
 var regex = /^(\d{2})\/(\d{2})\/(\d{4})$/;
 if(!regex.test(v)) return false;
 var d = new Date(v.replace(regex, '$2/$1/$3'));
 return ( parseInt(RegExp.$2, 10) == (1+d.getMonth()) ) &&
 (parseInt(RegExp.$1, 10) == d.getDate()) &&
 (parseInt(RegExp.$3, 10) == d.getFullYear() );
 }],
 ['validate-currency-dollar', 'Please enter a valid $ amount. For example $100.00.', function(v) {
 // [$]1[##][,###]+[.##]
 // [$]1###+[.##]
 // [$]0.##
 // [$].##
 return Validation.get('IsEmpty').test(v) || /^\$?\-?([1-9]{1}[0-9]{0,2}(\,[0-9]{3})*(\.[0-9]{0,2})?|[1-9]{1}\d*(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|(\.[0-9]{1,2})?)$/.test(v)
 }],
 ['validate-one-required', 'Please select one of the above options.', function (v,elm) {
 var p = elm.parentNode;
 var options = p.getElementsByTagName('INPUT');
 return $A(options).any(function(elm) {
 return $F(elm);
 });
 }],
 ['validate-one-required-by-name', 'Please select one of the options.', function (v,elm) {
 var inputs = $$('input[name="' + elm.name.replace(/([\\"])/g, '\\$1') + '"]');
 
 var error = 1;
 for(var i=0;i<inputs.length;i++) {
 if((inputs[i].type == 'checkbox' || inputs[i].type == 'radio') && inputs[i].checked == true) {
 error = 0;
 }
 
 if(Validation.isOnChange && (inputs[i].type == 'checkbox' || inputs[i].type == 'radio')) {
 Validation.reset(inputs[i]);
 }
 }

 if( error == 0 ) {
 return true;
 } else {
 return false;
 }
 }],
 ['validate-not-negative-number', 'Please enter a valid number in this field.', function(v) {
 v = parseNumber(v);
 return (!isNaN(v) && v>=0);
 }],
 ['validate-state', 'Please select State/Province.', function(v) {
 return (v!=0 || v == '');
 }],

 ['validate-new-password', 'Please enter 6 or more characters. Leading or trailing spaces will be ignored.', function(v) {
 if (!Validation.get('validate-password').test(v)) return false;
 if (Validation.get('IsEmpty').test(v) && v != '') return false;
 return true;
 }],
 ['validate-greater-than-zero', 'Please enter a number greater than 0 in this field.', function(v) {
 if(v.length)
 return parseFloat(v) > 0;
 else
 return true;
 }],
 ['validate-zero-or-greater', 'Please enter a number 0 or greater in this field.', function(v) {
 if(v.length)
 return parseFloat(v) >= 0;
 else
 return true;
 }],
 ['validate-cc-number', 'Please enter a valid credit card number.', function(v, elm) {
 // remove non-numerics
 var ccTypeContainer = $(elm.id.substr(0,elm.id.indexOf('_cc_number')) + '_cc_type');
 if (ccTypeContainer && typeof Validation.creditCartTypes.get(ccTypeContainer.value) != 'undefined'
 && Validation.creditCartTypes.get(ccTypeContainer.value)[2] == false) {
 if (!Validation.get('IsEmpty').test(v) && Validation.get('validate-digits').test(v)) {
 return true;
 } else {
 return false;
 }
 }
 return validateCreditCard(v);
 }],
 ['validate-cc-type', 'Credit card number doesn\'t match credit card type', function(v, elm) {
 // remove credit card number delimiters such as "-" and space
 elm.value = removeDelimiters(elm.value);
 v = removeDelimiters(v);

 var ccTypeContainer = $(elm.id.substr(0,elm.id.indexOf('_cc_number')) + '_cc_type');
 if (!ccTypeContainer) {
 return true;
 }
 var ccType = ccTypeContainer.value;

 if (typeof Validation.creditCartTypes.get(ccType) == 'undefined') {
 return false;
 }

 // Other card type or switch or solo card
 if (Validation.creditCartTypes.get(ccType)[0]==false) {
 return true;
 }

 // Matched credit card type
 var ccMatchedType = '';

 Validation.creditCartTypes.each(function (pair) {
 if (pair.value[0] && v.match(pair.value[0])) {
 ccMatchedType = pair.key;
 throw $break;
 }
 });

 if(ccMatchedType != ccType) {
 return false;
 }
 
 if (ccTypeContainer.hasClassName('validation-failed') && Validation.isOnChange) {
 Validation.validate(ccTypeContainer);
 }

 return true;
 }],
 ['validate-cc-type-select', 'Card type doesn\'t match credit card number', function(v, elm) {
 var ccNumberContainer = $(elm.id.substr(0,elm.id.indexOf('_cc_type')) + '_cc_number');
 if (Validation.isOnChange && Validation.get('IsEmpty').test(ccNumberContainer.value)) {
 return true;
 }
 if (Validation.get('validate-cc-type').test(ccNumberContainer.value, ccNumberContainer)) {
 Validation.validate(ccNumberContainer);
 }
 return Validation.get('validate-cc-type').test(ccNumberContainer.value, ccNumberContainer);
 }],
 ['validate-cc-exp', 'Incorrect credit card expiration date', function(v, elm) {
 var ccExpMonth = v;
 var ccExpYear = $('ccsave_expiration_yr').value;
 var currentTime = new Date();
 var currentMonth = currentTime.getMonth() + 1;
 var currentYear = currentTime.getFullYear();
 if (ccExpMonth < currentMonth && ccExpYear == currentYear) {
 return false;
 }
 return true;
 }],
 ['validate-cc-cvn', 'Please enter a valid credit card verification number.', function(v, elm) {
 var ccTypeContainer = $(elm.id.substr(0,elm.id.indexOf('_cc_cid')) + '_cc_type');
 if (!ccTypeContainer) {
 return true;
 }
 var ccType = ccTypeContainer.value;

 if (typeof Validation.creditCartTypes.get(ccType) == 'undefined') {
 return false;
 }

 var re = Validation.creditCartTypes.get(ccType)[1];

 if (v.match(re)) {
 return true;
 }

 return false;
 }],
 ['validate-ajax', '', function(v, elm) { return true; }],
 ['validate-data', 'Please use only letters (a-z or A-Z), numbers (0-9) or underscore(_) in this field, first character should be a letter.', function (v) {
 if(v != '' && v) {
 return /^[A-Za-z]+[A-Za-z0-9_]+$/.test(v);
 }
 return true;
 }],
 ['validate-css-length', 'Please input a valid CSS-length. For example 100px or 77pt or 20em or .5ex or 50%', function (v) {
 if (v != '' && v) {
 return /^[0-9\.]+(px|pt|em|ex|%)?$/.test(v) && (!(/\..*\./.test(v))) && !(/\.$/.test(v));
 }
 return true;
 }],
 ['validate-length', 'Maximum length exceeded.', function (v, elm) {
 var re = new RegExp(/^maximum-length-[0-9]+$/);
 var result = true;
 $w(elm.className).each(function(name, index) {
 if (name.match(re) && result) {
 var length = name.split('-')[2];
 result = (v.length <= length);
 }
 });
 return result;
 }]
]);


// Credit Card Validation Javascript
// copyright 12th May 2003, by Stephen Chapman, Felgall Pty Ltd

// You have permission to copy and use this javascript provided that
// the content of the script is not changed in any way.

function validateCreditCard(s) {
 // remove non-numerics
 var v = "0123456789";
 var w = "";
 for (i=0; i < s.length; i++) {
 x = s.charAt(i);
 if (v.indexOf(x,0) != -1)
 w += x;
 }
 // validate number
 j = w.length / 2;
 k = Math.floor(j);
 m = Math.ceil(j) - k;
 c = 0;
 for (i=0; i<k; i++) {
 a = w.charAt(i*2+m) * 2;
 c += a > 9 ? Math.floor(a/10 + a%10) : a;
 }
 for (i=0; i<k+m; i++) c += w.charAt(i*2+1-m) * 1;
 return (c%10 == 0);
}

function removeDelimiters (v) {
 v = v.replace(/\s/g, '');
 v = v.replace(/\-/g, '');
 return v;
}

function parseNumber(v)
{
 if (typeof v != 'string') {
 return parseFloat(v);
 }

 var isDot = v.indexOf('.');
 var isComa = v.indexOf(',');

 if (isDot != -1 && isComa != -1) {
 if (isComa > isDot) {
 v = v.replace('.', '').replace(',', '.');
 }
 else {
 v = v.replace(',', '');
 }
 }
 else if (isComa != -1) {
 v = v.replace(',', '.');
 }

 return parseFloat(v);
}

/**
 * Hash with credit card types wich can be simply extended in payment modules
 * 0 - regexp for card number
 * 1 - regexp for cvn
 * 2 - check or not credit card number trough Luhn algorithm by
 * function validateCreditCard wich you can find above in this file
 */
Validation.creditCartTypes = $H({
 'VI': [new RegExp('^4[0-9]{12}([0-9]{3})?$'), new RegExp('^[0-9]{3}$'), true],
 'MC': [new RegExp('^5[1-5][0-9]{14}$'), new RegExp('^[0-9]{3}$'), true],
 'AE': [new RegExp('^3[47][0-9]{13}$'), new RegExp('^[0-9]{4}$'), true],
 'DI': [new RegExp('^6011[0-9]{12}$'), new RegExp('^[0-9]{3}$'), true],
 'SS': [new RegExp('^((6759[0-9]{12})|(49[013][1356][0-9]{13})|(633[34][0-9]{12})|(633110[0-9]{10})|(564182[0-9]{10}))([0-9]{2,3})?$'), new RegExp('^([0-9]{3}|[0-9]{4})?$'), true],
 'OT': [false, new RegExp('^([0-9]{3}|[0-9]{4})?$'), false]
});

// script.aculo.us builder.js v1.7.1_beta3, Fri May 25 17:19:41 +0200 2007

// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/

var Builder = {
 NODEMAP: {
 AREA: 'map',
 CAPTION: 'table',
 COL: 'table',
 COLGROUP: 'table',
 LEGEND: 'fieldset',
 OPTGROUP: 'select',
 OPTION: 'select',
 PARAM: 'object',
 TBODY: 'table',
 TD: 'table',
 TFOOT: 'table',
 TH: 'table',
 THEAD: 'table',
 TR: 'table'
 },
 // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken,
 // due to a Firefox bug
 node: function(elementName) {
 elementName = elementName.toUpperCase();
 
 // try innerHTML approach
 var parentTag = this.NODEMAP[elementName] || 'div';
 var parentElement = document.createElement(parentTag);
 try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
 parentElement.innerHTML = "<" + elementName + "></" + elementName + ">";
 } catch(e) {}
 var element = parentElement.firstChild || null;
 
 // see if browser added wrapping tags
 if(element && (element.tagName.toUpperCase() != elementName))
 element = element.getElementsByTagName(elementName)[0];
 
 // fallback to createElement approach
 if(!element) element = document.createElement(elementName);
 
 // abort if nothing could be created
 if(!element) return;

 // attributes (or text)
 if(arguments[1])
 if(this._isStringOrNumber(arguments[1]) ||
 (arguments[1] instanceof Array) ||
 arguments[1].tagName) {
 this._children(element, arguments[1]);
 } else {
 var attrs = this._attributes(arguments[1]);
 if(attrs.length) {
 try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
 parentElement.innerHTML = "<" +elementName + " " +
 attrs + "></" + elementName + ">";
 } catch(e) {}
 element = parentElement.firstChild || null;
 // workaround firefox 1.0.X bug
 if(!element) {
 element = document.createElement(elementName);
 for(attr in arguments[1]) 
 element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
 }
 if(element.tagName.toUpperCase() != elementName)
 element = parentElement.getElementsByTagName(elementName)[0];
 }
 } 

 // text, or array of children
 if(arguments[2])
 this._children(element, arguments[2]);

 return element;
 },
 _text: function(text) {
 return document.createTextNode(text);
 },

 ATTR_MAP: {
 'className': 'class',
 'htmlFor': 'for'
 },

 _attributes: function(attributes) {
 var attrs = [];
 for(attribute in attributes)
 attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) +
 '="' + attributes[attribute].toString().escapeHTML().gsub(/"/,'&quot;') + '"');
 return attrs.join(" ");
 },
 _children: function(element, children) {
 if(children.tagName) {
 element.appendChild(children);
 return;
 }
 if(typeof children=='object') { // array can hold nodes and text
 children.flatten().each( function(e) {
 if(typeof e=='object')
 element.appendChild(e)
 else
 if(Builder._isStringOrNumber(e))
 element.appendChild(Builder._text(e));
 });
 } else
 if(Builder._isStringOrNumber(children))
 element.appendChild(Builder._text(children));
 },
 _isStringOrNumber: function(param) {
 return(typeof param=='string' || typeof param=='number');
 },
 build: function(html) {
 var element = this.node('div');
 $(element).update(html.strip());
 return element.down();
 },
 dump: function(scope) { 
 if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope 
 
 var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " +
 "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " +
 "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+
 "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+
 "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+
 "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);
 
 tags.each( function(tag){ 
 scope[tag] = function() { 
 return Builder.node.apply(Builder, [tag].concat($A(arguments))); 
 } 
 });
 }
}

// script.aculo.us effects.js v1.7.1_beta3, Fri May 25 17:19:41 +0200 2007

// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// Contributors:
// Justin Palmer (http://encytemedia.com/)
// Mark Pilgrim (http://diveintomark.org/)
// Martin Bialasinki
// 
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/ 

// converts rgb() and #xxx to #xxxxxx format, 
// returns self (or first argument) if not convertable 
String.prototype.parseColor = function() { 
 var color = '#';
 if(this.slice(0,4) == 'rgb(') { 
 var cols = this.slice(4,this.length-1).split(','); 
 var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3); 
 } else { 
 if(this.slice(0,1) == '#') { 
 if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase(); 
 if(this.length==7) color = this.toLowerCase(); 
 } 
 } 
 return(color.length==7 ? color : (arguments[0] || this)); 
}

/*--------------------------------------------------------------------------*/

Element.collectTextNodes = function(element) { 
 return $A($(element).childNodes).collect( function(node) {
 return (node.nodeType==3 ? node.nodeValue : 
 (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
 }).flatten().join('');
}

Element.collectTextNodesIgnoreClass = function(element, className) { 
 return $A($(element).childNodes).collect( function(node) {
 return (node.nodeType==3 ? node.nodeValue : 
 ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? 
 Element.collectTextNodesIgnoreClass(node, className) : ''));
 }).flatten().join('');
}

Element.setContentZoom = function(element, percent) {
 element = $(element); 
 element.setStyle({fontSize: (percent/100) + 'em'}); 
 if(Prototype.Browser.WebKit) window.scrollBy(0,0);
 return element;
}

Element.getInlineOpacity = function(element){
 return $(element).style.opacity || '';
}

Element.forceRerendering = function(element) {
 try {
 element = $(element);
 var n = document.createTextNode(' ');
 element.appendChild(n);
 element.removeChild(n);
 } catch(e) { }
};

/*--------------------------------------------------------------------------*/

Array.prototype.call = function() {
 var args = arguments;
 this.each(function(f){ f.apply(this, args) });
}

/*--------------------------------------------------------------------------*/

var Effect = {
 _elementDoesNotExistError: {
 name: 'ElementDoesNotExistError',
 message: 'The specified DOM element does not exist, but is required for this effect to operate'
 },
 tagifyText: function(element) {
 if(typeof Builder == 'undefined')
 throw("Effect.tagifyText requires including script.aculo.us' builder.js library");
 
 var tagifyStyle = 'position:relative';
 if(Prototype.Browser.IE) tagifyStyle += ';zoom:1';
 
 element = $(element);
 $A(element.childNodes).each( function(child) {
 if(child.nodeType==3) {
 child.nodeValue.toArray().each( function(character) {
 element.insertBefore(
 Builder.node('span',{style: tagifyStyle},
 character == ' ' ? String.fromCharCode(160) : character), 
 child);
 });
 Element.remove(child);
 }
 });
 },
 multiple: function(element, effect) {
 var elements;
 if(((typeof element == 'object') || 
 (typeof element == 'function')) && 
 (element.length))
 elements = element;
 else
 elements = $(element).childNodes;
 
 var options = Object.extend({
 speed: 0.1,
 delay: 0.0
 }, arguments[2] || {});
 var masterDelay = options.delay;

 $A(elements).each( function(element, index) {
 new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
 });
 },
 PAIRS: {
 'slide': ['SlideDown','SlideUp'],
 'blind': ['BlindDown','BlindUp'],
 'appear': ['Appear','Fade']
 },
 toggle: function(element, effect) {
 element = $(element);
 effect = (effect || 'appear').toLowerCase();
 var options = Object.extend({
 queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
 }, arguments[2] || {});
 Effect[element.visible() ? 
 Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
 }
};

var Effect2 = Effect; // deprecated

/* ------------- transitions ------------- */

Effect.Transitions = {
 linear: Prototype.K,
 sinoidal: function(pos) {
 return (-Math.cos(pos*Math.PI)/2) + 0.5;
 },
 reverse: function(pos) {
 return 1-pos;
 },
 flicker: function(pos) {
 var pos = ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
 return (pos > 1 ? 1 : pos);
 },
 wobble: function(pos) {
 return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
 },
 pulse: function(pos, pulses) { 
 pulses = pulses || 5; 
 return (
 Math.round((pos % (1/pulses)) * pulses) == 0 ? 
 ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) : 
 1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2))
 );
 },
 none: function(pos) {
 return 0;
 },
 full: function(pos) {
 return 1;
 }
};

/* ------------- core effects ------------- */

Effect.ScopedQueue = Class.create();
Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
 initialize: function() {
 this.effects = [];
 this.interval = null; 
 },
 _each: function(iterator) {
 this.effects._each(iterator);
 },
 add: function(effect) {
 var timestamp = new Date().getTime();
 
 var position = (typeof effect.options.queue == 'string') ? 
 effect.options.queue : effect.options.queue.position;
 
 switch(position) {
 case 'front':
 // move unstarted effects after this effect 
 this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
 e.startOn += effect.finishOn;
 e.finishOn += effect.finishOn;
 });
 break;
 case 'with-last':
 timestamp = this.effects.pluck('startOn').max() || timestamp;
 break;
 case 'end':
 // start effect after last queued effect has finished
 timestamp = this.effects.pluck('finishOn').max() || timestamp;
 break;
 }
 
 effect.startOn += timestamp;
 effect.finishOn += timestamp;

 if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
 this.effects.push(effect);
 
 if(!this.interval)
 this.interval = setInterval(this.loop.bind(this), 15);
 },
 remove: function(effect) {
 this.effects = this.effects.reject(function(e) { return e==effect });
 if(this.effects.length == 0) {
 clearInterval(this.interval);
 this.interval = null;
 }
 },
 loop: function() {
 var timePos = new Date().getTime();
 for(var i=0, len=this.effects.length;i<len;i++) 
 this.effects[i] && this.effects[i].loop(timePos);
 }
});

Effect.Queues = {
 instances: $H(),
 get: function(queueName) {
 if(typeof queueName != 'string') return queueName;
 
 if(!this.instances[queueName])
 this.instances[queueName] = new Effect.ScopedQueue();
 
 return this.instances[queueName];
 }
}
Effect.Queue = Effect.Queues.get('global');

Effect.DefaultOptions = {
 transition: Effect.Transitions.sinoidal,
 duration: 1.0, // seconds
 fps: 100, // 100= assume 66fps max.
 sync: false, // true for combining
 from: 0.0,
 to: 1.0,
 delay: 0.0,
 queue: 'parallel'
}

Effect.Base = function() {};
Effect.Base.prototype = {
 position: null,
 start: function(options) {
 function codeForEvent(options,eventName){
 return (
 (options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') +
 (options[eventName] ? 'this.options.'+eventName+'(this);' : '')
 );
 }
 if(options.transition === false) options.transition = Effect.Transitions.linear;
 this.options = Object.extend(Object.extend({},Effect.DefaultOptions), options || {});
 this.currentFrame = 0;
 this.state = 'idle';
 this.startOn = this.options.delay*1000;
 this.finishOn = this.startOn+(this.options.duration*1000);
 this.fromToDelta = this.options.to-this.options.from;
 this.totalTime = this.finishOn-this.startOn;
 this.totalFrames = this.options.fps*this.options.duration;
 
 eval('this.render = function(pos){ '+
 'if(this.state=="idle"){this.state="running";'+
 codeForEvent(options,'beforeSetup')+
 (this.setup ? 'this.setup();':'')+ 
 codeForEvent(options,'afterSetup')+
 '};if(this.state=="running"){'+
 'pos=this.options.transition(pos)*'+this.fromToDelta+'+'+this.options.from+';'+
 'this.position=pos;'+
 codeForEvent(options,'beforeUpdate')+
 (this.update ? 'this.update(pos);':'')+
 codeForEvent(options,'afterUpdate')+
 '}}');
 
 this.event('beforeStart');
 if(!this.options.sync)
 Effect.Queues.get(typeof this.options.queue == 'string' ? 
 'global' : this.options.queue.scope).add(this);
 },
 loop: function(timePos) {
 if(timePos >= this.startOn) {
 if(timePos >= this.finishOn) {
 this.render(1.0);
 this.cancel();
 this.event('beforeFinish');
 if(this.finish) this.finish(); 
 this.event('afterFinish');
 return; 
 }
 var pos = (timePos - this.startOn) / this.totalTime,
 frame = Math.round(pos * this.totalFrames);
 if(frame > this.currentFrame) {
 this.render(pos);
 this.currentFrame = frame;
 }
 }
 },
 cancel: function() {
 if(!this.options.sync)
 Effect.Queues.get(typeof this.options.queue == 'string' ? 
 'global' : this.options.queue.scope).remove(this);
 this.state = 'finished';
 },
 event: function(eventName) {
 if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
 if(this.options[eventName]) this.options[eventName](this);
 },
 inspect: function() {
 var data = $H();
 for(property in this)
 if(typeof this[property] != 'function') data[property] = this[property];
 return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
 }
}

Effect.Parallel = Class.create();
Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
 initialize: function(effects) {
 this.effects = effects || [];
 this.start(arguments[1]);
 },
 update: function(position) {
 this.effects.invoke('render', position);
 },
 finish: function(position) {
 this.effects.each( function(effect) {
 effect.render(1.0);
 effect.cancel();
 effect.event('beforeFinish');
 if(effect.finish) effect.finish(position);
 effect.event('afterFinish');
 });
 }
});

Effect.Event = Class.create();
Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), {
 initialize: function() {
 var options = Object.extend({
 duration: 0
 }, arguments[0] || {});
 this.start(options);
 },
 update: Prototype.emptyFunction
});

Effect.Opacity = Class.create();
Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
 initialize: function(element) {
 this.element = $(element);
 if(!this.element) throw(Effect._elementDoesNotExistError);
 // make this work on IE on elements without 'layout'
 if(Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
 this.element.setStyle({zoom: 1});
 var options = Object.extend({
 from: this.element.getOpacity() || 0.0,
 to: 1.0
 }, arguments[1] || {});
 this.start(options);
 },
 update: function(position) {
 this.element.setOpacity(position);
 }
});

Effect.Move = Class.create();
Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
 initialize: function(element) {
 this.element = $(element);
 if(!this.element) throw(Effect._elementDoesNotExistError);
 var options = Object.extend({
 x: 0,
 y: 0,
 mode: 'relative'
 }, arguments[1] || {});
 this.start(options);
 },
 setup: function() {
 // Bug in Opera: Opera returns the "real" position of a static element or
 // relative element that does not have top/left explicitly set.
 // ==> Always set top and left for position relative elements in your stylesheets 
 // (to 0 if you do not need them) 
 this.element.makePositioned();
 this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
 this.originalTop = parseFloat(this.element.getStyle('top') || '0');
 if(this.options.mode == 'absolute') {
 // absolute movement, so we need to calc deltaX and deltaY
 this.options.x = this.options.x - this.originalLeft;
 this.options.y = this.options.y - this.originalTop;
 }
 },
 update: function(position) {
 this.element.setStyle({
 left: Math.round(this.options.x * position + this.originalLeft) + 'px',
 top: Math.round(this.options.y * position + this.originalTop) + 'px'
 });
 }
});

// for backwards compatibility
Effect.MoveBy = function(element, toTop, toLeft) {
 return new Effect.Move(element, 
 Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));
};

Effect.Scale = Class.create();
Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
 initialize: function(element, percent) {
 this.element = $(element);
 if(!this.element) throw(Effect._elementDoesNotExistError);
 var options = Object.extend({
 scaleX: true,
 scaleY: true,
 scaleContent: true,
 scaleFromCenter: false,
 scaleMode: 'box', // 'box' or 'contents' or {} with provided values
 scaleFrom: 100.0,
 scaleTo: percent
 }, arguments[2] || {});
 this.start(options);
 },
 setup: function() {
 this.restoreAfterFinish = this.options.restoreAfterFinish || false;
 this.elementPositioning = this.element.getStyle('position');
 
 this.originalStyle = {};
 ['top','left','width','height','fontSize'].each( function(k) {
 this.originalStyle[k] = this.element.style[k];
 }.bind(this));
 
 this.originalTop = this.element.offsetTop;
 this.originalLeft = this.element.offsetLeft;
 
 var fontSize = this.element.getStyle('font-size') || '100%';
 ['em','px','%','pt'].each( function(fontSizeType) {
 if(fontSize.indexOf(fontSizeType)>0) {
 this.fontSize = parseFloat(fontSize);
 this.fontSizeType = fontSizeType;
 }
 }.bind(this));
 
 this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
 
 this.dims = null;
 if(this.options.scaleMode=='box')
 this.dims = [this.element.offsetHeight, this.element.offsetWidth];
 if(/^content/.test(this.options.scaleMode))
 this.dims = [this.element.scrollHeight, this.element.scrollWidth];
 if(!this.dims)
 this.dims = [this.options.scaleMode.originalHeight,
 this.options.scaleMode.originalWidth];
 },
 update: function(position) {
 var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
 if(this.options.scaleContent && this.fontSize)
 this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
 this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
 },
 finish: function(position) {
 if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
 },
 setDimensions: function(height, width) {
 var d = {};
 if(this.options.scaleX) d.width = Math.round(width) + 'px';
 if(this.options.scaleY) d.height = Math.round(height) + 'px';
 if(this.options.scaleFromCenter) {
 var topd = (height - this.dims[0])/2;
 var leftd = (width - this.dims[1])/2;
 if(this.elementPositioning == 'absolute') {
 if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
 if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
 } else {
 if(this.options.scaleY) d.top = -topd + 'px';
 if(this.options.scaleX) d.left = -leftd + 'px';
 }
 }
 this.element.setStyle(d);
 }
});

Effect.Highlight = Class.create();
Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
 initialize: function(element) {
 this.element = $(element);
 if(!this.element) throw(Effect._elementDoesNotExistError);
 var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
 this.start(options);
 },
 setup: function() {
 // Prevent executing on elements not in the layout flow
 if(this.element.getStyle('display')=='none') { this.cancel(); return; }
 // Disable background image during the effect
 this.oldStyle = {};
 if (!this.options.keepBackgroundImage) {
 this.oldStyle.backgroundImage = this.element.getStyle('background-image');
 this.element.setStyle({backgroundImage: 'none'});
 }
 if(!this.options.endcolor)
 this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
 if(!this.options.restorecolor)
 this.options.restorecolor = this.element.getStyle('background-color');
 // init color calculations
 this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
 this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
 },
 update: function(position) {
 this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
 return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });
 },
 finish: function() {
 this.element.setStyle(Object.extend(this.oldStyle, {
 backgroundColor: this.options.restorecolor
 }));
 }
});

Effect.ScrollTo = Class.create();
Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
 initialize: function(element) {
 this.element = $(element);
 this.start(arguments[1] || {});
 },
 setup: function() {
 Position.prepare();
 var offsets = Position.cumulativeOffset(this.element);
 if(this.options.offset) offsets[1] += this.options.offset;
 var max = window.innerHeight ? 
 window.height - window.innerHeight :
 document.body.scrollHeight - 
 (document.documentElement.clientHeight ? 
 document.documentElement.clientHeight : document.body.clientHeight);
 this.scrollStart = Position.deltaY;
 this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;
 },
 update: function(position) {
 Position.prepare();
 window.scrollTo(Position.deltaX, 
 this.scrollStart + (position*this.delta));
 }
});

/* ------------- combination effects ------------- */

Effect.Fade = function(element) {
 element = $(element);
 var oldOpacity = element.getInlineOpacity();
 var options = Object.extend({
 from: element.getOpacity() || 1.0,
 to: 0.0,
 afterFinishInternal: function(effect) { 
 if(effect.options.to!=0) return;
 effect.element.hide().setStyle({opacity: oldOpacity}); 
 }}, arguments[1] || {});
 return new Effect.Opacity(element,options);
}

Effect.Appear = function(element) {
 element = $(element);
 var options = Object.extend({
 from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
 to: 1.0,
 // force Safari to render floated elements properly
 afterFinishInternal: function(effect) {
 effect.element.forceRerendering();
 },
 beforeSetup: function(effect) {
 effect.element.setOpacity(effect.options.from).show(); 
 }}, arguments[1] || {});
 return new Effect.Opacity(element,options);
}

Effect.Puff = function(element) {
 element = $(element);
 var oldStyle = { 
 opacity: element.getInlineOpacity(), 
 position: element.getStyle('position'),
 top: element.style.top,
 left: element.style.left,
 width: element.style.width,
 height: element.style.height
 };
 return new Effect.Parallel(
 [ new Effect.Scale(element, 200, 
 { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), 
 new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], 
 Object.extend({ duration: 1.0, 
 beforeSetupInternal: function(effect) {
 Position.absolutize(effect.effects[0].element)
 },
 afterFinishInternal: function(effect) {
 effect.effects[0].element.hide().setStyle(oldStyle); }
 }, arguments[1] || {})
 );
}

Effect.BlindUp = function(element) {
 element = $(element);
 element.makeClipping();
 return new Effect.Scale(element, 0,
 Object.extend({ scaleContent: false, 
 scaleX: false, 
 restoreAfterFinish: true,
 afterFinishInternal: function(effect) {
 effect.element.hide().undoClipping();
 } 
 }, arguments[1] || {})
 );
}

Effect.BlindDown = function(element) {
 element = $(element);
 var elementDimensions = element.getDimensions();
 return new Effect.Scale(element, 100, Object.extend({ 
 scaleContent: false, 
 scaleX: false,
 scaleFrom: 0,
 scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
 restoreAfterFinish: true,
 afterSetup: function(effect) {
 effect.element.makeClipping().setStyle({height: '0px'}).show(); 
 }, 
 afterFinishInternal: function(effect) {
 effect.element.undoClipping();
 }
 }, arguments[1] || {}));
}

Effect.SwitchOff = function(element) {
 element = $(element);
 var oldOpacity = element.getInlineOpacity();
 return new Effect.Appear(element, Object.extend({
 duration: 0.4,
 from: 0,
 transition: Effect.Transitions.flicker,
 afterFinishInternal: function(effect) {
 new Effect.Scale(effect.element, 1, { 
 duration: 0.3, scaleFromCenter: true,
 scaleX: false, scaleContent: false, restoreAfterFinish: true,
 beforeSetup: function(effect) { 
 effect.element.makePositioned().makeClipping();
 },
 afterFinishInternal: function(effect) {
 effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
 }
 })
 }
 }, arguments[1] || {}));
}

Effect.DropOut = function(element) {
 element = $(element);
 var oldStyle = {
 top: element.getStyle('top'),
 left: element.getStyle('left'),
 opacity: element.getInlineOpacity() };
 return new Effect.Parallel(
 [ new Effect.Move(element, {x: 0, y: 100, sync: true }), 
 new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
 Object.extend(
 { duration: 0.5,
 beforeSetup: function(effect) {
 effect.effects[0].element.makePositioned(); 
 },
 afterFinishInternal: function(effect) {
 effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
 } 
 }, arguments[1] || {}));
}

Effect.Shake = function(element) {
 element = $(element);
 var oldStyle = {
 top: element.getStyle('top'),
 left: element.getStyle('left') };
 return new Effect.Move(element, 
 { x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
 new Effect.Move(effect.element,
 { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
 new Effect.Move(effect.element,
 { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
 new Effect.Move(effect.element,
 { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
 new Effect.Move(effect.element,
 { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
 new Effect.Move(effect.element,
 { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
 effect.element.undoPositioned().setStyle(oldStyle);
 }}) }}) }}) }}) }}) }});
}

Effect.SlideDown = function(element) {
 element = $(element).cleanWhitespace();
 // SlideDown need to have the content of the element wrapped in a container element with fixed height!
 var oldInnerBottom = element.down().getStyle('bottom');
 var elementDimensions = element.getDimensions();
 return new Effect.Scale(element, 100, Object.extend({ 
 scaleContent: false, 
 scaleX: false, 
 scaleFrom: window.opera ? 0 : 1,
 scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
 restoreAfterFinish: true,
 afterSetup: function(effect) {
 effect.element.makePositioned();
 effect.element.down().makePositioned();
 if(window.opera) effect.element.setStyle({top: ''});
 effect.element.makeClipping().setStyle({height: '0px'}).show(); 
 },
 afterUpdateInternal: function(effect) {
 effect.element.down().setStyle({bottom:
 (effect.dims[0] - effect.element.clientHeight) + 'px' }); 
 },
 afterFinishInternal: function(effect) {
 effect.element.undoClipping().undoPositioned();
 effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
 }, arguments[1] || {})
 );
}

Effect.SlideUp = function(element) {
 element = $(element).cleanWhitespace();
 var oldInnerBottom = element.down().getStyle('bottom');
 return new Effect.Scale(element, window.opera ? 0 : 1,
 Object.extend({ scaleContent: false, 
 scaleX: false, 
 scaleMode: 'box',
 scaleFrom: 100,
 restoreAfterFinish: true,
 beforeStartInternal: function(effect) {
 effect.element.makePositioned();
 effect.element.down().makePositioned();
 if(window.opera) effect.element.setStyle({top: ''});
 effect.element.makeClipping().show();
 }, 
 afterUpdateInternal: function(effect) {
 effect.element.down().setStyle({bottom:
 (effect.dims[0] - effect.element.clientHeight) + 'px' });
 },
 afterFinishInternal: function(effect) {
 effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom});
 effect.element.down().undoPositioned();
 }
 }, arguments[1] || {})
 );
}

// Bug in opera makes the TD containing this element expand for a instance after finish 
Effect.Squish = function(element) {
 return new Effect.Scale(element, window.opera ? 1 : 0, { 
 restoreAfterFinish: true,
 beforeSetup: function(effect) {
 effect.element.makeClipping(); 
 }, 
 afterFinishInternal: function(effect) {
 effect.element.hide().undoClipping(); 
 }
 });
}

Effect.Grow = function(element) {
 element = $(element);
 var options = Object.extend({
 direction: 'center',
 moveTransition: Effect.Transitions.sinoidal,
 scaleTransition: Effect.Transitions.sinoidal,
 opacityTransition: Effect.Transitions.full
 }, arguments[1] || {});
 var oldStyle = {
 top: element.style.top,
 left: element.style.left,
 height: element.style.height,
 width: element.style.width,
 opacity: element.getInlineOpacity() };

 var dims = element.getDimensions(); 
 var initialMoveX, initialMoveY;
 var moveX, moveY;
 
 switch (options.direction) {
 case 'top-left':
 initialMoveX = initialMoveY = moveX = moveY = 0; 
 break;
 case 'top-right':
 initialMoveX = dims.width;
 initialMoveY = moveY = 0;
 moveX = -dims.width;
 break;
 case 'bottom-left':
 initialMoveX = moveX = 0;
 initialMoveY = dims.height;
 moveY = -dims.height;
 break;
 case 'bottom-right':
 initialMoveX = dims.width;
 initialMoveY = dims.height;
 moveX = -dims.width;
 moveY = -dims.height;
 break;
 case 'center':
 initialMoveX = dims.width / 2;
 initialMoveY = dims.height / 2;
 moveX = -dims.width / 2;
 moveY = -dims.height / 2;
 break;
 }
 
 return new Effect.Move(element, {
 x: initialMoveX,
 y: initialMoveY,
 duration: 0.01, 
 beforeSetup: function(effect) {
 effect.element.hide().makeClipping().makePositioned();
 },
 afterFinishInternal: function(effect) {
 new Effect.Parallel(
 [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
 new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
 new Effect.Scale(effect.element, 100, {
 scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, 
 sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
 ], Object.extend({
 beforeSetup: function(effect) {
 effect.effects[0].element.setStyle({height: '0px'}).show(); 
 },
 afterFinishInternal: function(effect) {
 effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); 
 }
 }, options)
 )
 }
 });
}

Effect.Shrink = function(element) {
 element = $(element);
 var options = Object.extend({
 direction: 'center',
 moveTransition: Effect.Transitions.sinoidal,
 scaleTransition: Effect.Transitions.sinoidal,
 opacityTransition: Effect.Transitions.none
 }, arguments[1] || {});
 var oldStyle = {
 top: element.style.top,
 left: element.style.left,
 height: element.style.height,
 width: element.style.width,
 opacity: element.getInlineOpacity() };

 var dims = element.getDimensions();
 var moveX, moveY;
 
 switch (options.direction) {
 case 'top-left':
 moveX = moveY = 0;
 break;
 case 'top-right':
 moveX = dims.width;
 moveY = 0;
 break;
 case 'bottom-left':
 moveX = 0;
 moveY = dims.height;
 break;
 case 'bottom-right':
 moveX = dims.width;
 moveY = dims.height;
 break;
 case 'center': 
 moveX = dims.width / 2;
 moveY = dims.height / 2;
 break;
 }
 
 return new Effect.Parallel(
 [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
 new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
 new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
 ], Object.extend({ 
 beforeStartInternal: function(effect) {
 effect.effects[0].element.makePositioned().makeClipping(); 
 },
 afterFinishInternal: function(effect) {
 effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
 }, options)
 );
}

Effect.Pulsate = function(element) {
 element = $(element);
 var options = arguments[1] || {};
 var oldOpacity = element.getInlineOpacity();
 var transition = options.transition || Effect.Transitions.sinoidal;
 var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
 reverser.bind(transition);
 return new Effect.Opacity(element, 
 Object.extend(Object.extend({ duration: 2.0, from: 0,
 afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
 }, options), {transition: reverser}));
}

Effect.Fold = function(element) {
 element = $(element);
 var oldStyle = {
 top: element.style.top,
 left: element.style.left,
 width: element.style.width,
 height: element.style.height };
 element.makeClipping();
 return new Effect.Scale(element, 5, Object.extend({ 
 scaleContent: false,
 scaleX: false,
 afterFinishInternal: function(effect) {
 new Effect.Scale(element, 1, { 
 scaleContent: false, 
 scaleY: false,
 afterFinishInternal: function(effect) {
 effect.element.hide().undoClipping().setStyle(oldStyle);
 } });
 }}, arguments[1] || {}));
};

Effect.Morph = Class.create();
Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), {
 initialize: function(element) {
 this.element = $(element);
 if(!this.element) throw(Effect._elementDoesNotExistError);
 var options = Object.extend({
 style: {}
 }, arguments[1] || {});
 if (typeof options.style == 'string') {
 if(options.style.indexOf(':') == -1) {
 var cssText = '', selector = '.' + options.style;
 $A(document.styleSheets).reverse().each(function(styleSheet) {
 if (styleSheet.cssRules) cssRules = styleSheet.cssRules;
 else if (styleSheet.rules) cssRules = styleSheet.rules;
 $A(cssRules).reverse().each(function(rule) {
 if (selector == rule.selectorText) {
 cssText = rule.style.cssText;
 throw $break;
 }
 });
 if (cssText) throw $break;
 });
 this.style = cssText.parseStyle();
 options.afterFinishInternal = function(effect){
 effect.element.addClassName(effect.options.style);
 effect.transforms.each(function(transform) {
 if(transform.style != 'opacity')
 effect.element.style[transform.style] = '';
 });
 }
 } else this.style = options.style.parseStyle();
 } else this.style = $H(options.style)
 this.start(options);
 },
 setup: function(){
 function parseColor(color){
 if(!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
 color = color.parseColor();
 return $R(0,2).map(function(i){
 return parseInt( color.slice(i*2+1,i*2+3), 16 ) 
 });
 }
 this.transforms = this.style.map(function(pair){
 var property = pair[0], value = pair[1], unit = null;

 if(value.parseColor('#zzzzzz') != '#zzzzzz') {
 value = value.parseColor();
 unit = 'color';
 } else if(property == 'opacity') {
 value = parseFloat(value);
 if(Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
 this.element.setStyle({zoom: 1});
 } else if(Element.CSS_LENGTH.test(value)) {
 var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
 value = parseFloat(components[1]);
 unit = (components.length == 3) ? components[2] : null;
 }

 var originalValue = this.element.getStyle(property);
 return { 
 style: property.camelize(), 
 originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), 
 targetValue: unit=='color' ? parseColor(value) : value,
 unit: unit
 };
 }.bind(this)).reject(function(transform){
 return (
 (transform.originalValue == transform.targetValue) ||
 (
 transform.unit != 'color' &&
 (isNaN(transform.originalValue) || isNaN(transform.targetValue))
 )
 )
 });
 },
 update: function(position) {
 var style = {}, transform, i = this.transforms.length;
 while(i--)
 style[(transform = this.transforms[i]).style] = 
 transform.unit=='color' ? '#'+
 (Math.round(transform.originalValue[0]+
 (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
 (Math.round(transform.originalValue[1]+
 (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
 (Math.round(transform.originalValue[2]+
 (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
 transform.originalValue + Math.round(
 ((transform.targetValue - transform.originalValue) * position) * 1000)/1000 + transform.unit;
 this.element.setStyle(style, true);
 }
});

Effect.Transform = Class.create();
Object.extend(Effect.Transform.prototype, {
 initialize: function(tracks){
 this.tracks = [];
 this.options = arguments[1] || {};
 this.addTracks(tracks);
 },
 addTracks: function(tracks){
 tracks.each(function(track){
 var data = $H(track).values().first();
 this.tracks.push($H({
 ids: $H(track).keys().first(),
 effect: Effect.Morph,
 options: { style: data }
 }));
 }.bind(this));
 return this;
 },
 play: function(){
 return new Effect.Parallel(
 this.tracks.map(function(track){
 var elements = [$(track.ids) || $$(track.ids)].flatten();
 return elements.map(function(e){ return new track.effect(e, Object.extend({ sync:true }, track.options)) });
 }).flatten(),
 this.options
 );
 }
});

Element.CSS_PROPERTIES = $w(
 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' + 
 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
 'fontSize fontWeight height left letterSpacing lineHeight ' +
 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
 'right textIndent top width wordSpacing zIndex');
 
Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;

String.prototype.parseStyle = function(){
 var element = document.createElement('div');
 element.innerHTML = '<div style="' + this + '"></div>';
 var style = element.childNodes[0].style, styleRules = $H();
 
 Element.CSS_PROPERTIES.each(function(property){
 if(style[property]) styleRules[property] = style[property]; 
 });
 if(Prototype.Browser.IE && this.indexOf('opacity') > -1) {
 styleRules.opacity = this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1];
 }
 return styleRules;
};

Element.morph = function(element, style) {
 new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {}));
 return element;
};

['getInlineOpacity','forceRerendering','setContentZoom',
 'collectTextNodes','collectTextNodesIgnoreClass','morph'].each( 
 function(f) { Element.Methods[f] = Element[f]; }
);

Element.Methods.visualEffect = function(element, effect, options) {
 s = effect.dasherize().camelize();
 effect_class = s.charAt(0).toUpperCase() + s.substring(1);
 new Effect[effect_class](element, options);
 return $(element);
};

Element.addMethods();
// script.aculo.us dragdrop.js v1.7.1_beta3, Fri May 25 17:19:41 +0200 2007

// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// (c) 2005-2007 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/

if(typeof Effect == 'undefined')
 throw("dragdrop.js requires including script.aculo.us' effects.js library");

var Droppables = {
 drops: [],

 remove: function(element) {
 this.drops = this.drops.reject(function(d) { return d.element==$(element) });
 },

 add: function(element) {
 element = $(element);
 var options = Object.extend({
 greedy: true,
 hoverclass: null,
 tree: false
 }, arguments[1] || {});

 // cache containers
 if(options.containment) {
 options._containers = [];
 var containment = options.containment;
 if((typeof containment == 'object') &&
 (containment.constructor == Array)) {
 containment.each( function(c) { options._containers.push($(c)) });
 } else {
 options._containers.push($(containment));
 }
 }

 if(options.accept) options.accept = [options.accept].flatten();

 Element.makePositioned(element); // fix IE
 options.element = element;

 this.drops.push(options);
 },

 findDeepestChild: function(drops) {
 deepest = drops[0];

 for (i = 1; i < drops.length; ++i)
 if (Element.isParent(drops[i].element, deepest.element))
 deepest = drops[i];

 return deepest;
 },

 isContained: function(element, drop) {
 var containmentNode;
 if(drop.tree) {
 containmentNode = element.treeNode;
 } else {
 containmentNode = element.parentNode;
 }
 return drop._containers.detect(function(c) { return containmentNode == c });
 },

 isAffected: function(point, element, drop) {
 return (
 (drop.element!=element) &&
 ((!drop._containers) ||
 this.isContained(element, drop)) &&
 ((!drop.accept) ||
 (Element.classNames(element).detect(
 function(v) { return drop.accept.include(v) } ) )) &&
 Position.within(drop.element, point[0], point[1]) );
 },

 deactivate: function(drop) {
 if(drop.hoverclass)
 Element.removeClassName(drop.element, drop.hoverclass);
 this.last_active = null;
 },

 activate: function(drop) {
 if(drop.hoverclass)
 Element.addClassName(drop.element, drop.hoverclass);
 this.last_active = drop;
 },

 show: function(point, element) {
 if(!this.drops.length) return;
 var affected = [];

 if(this.last_active) this.deactivate(this.last_active);
 this.drops.each( function(drop) {
 if(Droppables.isAffected(point, element, drop))
 affected.push(drop);
 });

 if(affected.length>0) {
 drop = Droppables.findDeepestChild(affected);
 Position.within(drop.element, point[0], point[1]);
 if(drop.onHover)
 drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));

 Droppables.activate(drop);
 }
 },

 fire: function(event, element) {
 if(!this.last_active) return;
 Position.prepare();

 if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
 if (this.last_active.onDrop) {
 this.last_active.onDrop(element, this.last_active.element, event);
 return true;
 }
 },

 reset: function() {
 if(this.last_active)
 this.deactivate(this.last_active);
 }
}

var Draggables = {
 drags: [],
 observers: [],

 register: function(draggable) {
 if(this.drags.length == 0) {
 this.eventMouseUp = this.endDrag.bindAsEventListener(this);
 this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
 this.eventKeypress = this.keyPress.bindAsEventListener(this);

 Event.observe(document, "mouseup", this.eventMouseUp);
 Event.observe(draggable.element, "mousemove", this.eventMouseMove);
 Event.observe(document, "keypress", this.eventKeypress);
 }
 this.drags.push(draggable);
 },

 unregister: function(draggable) {
 this.drags = this.drags.reject(function(d) { return d==draggable });
 if(this.drags.length == 0) {
 Event.stopObserving(document, "mouseup", this.eventMouseUp);
 Event.stopObserving(draggable.element, "mousemove", this.eventMouseMove);
 Event.stopObserving(document, "keypress", this.eventKeypress);
 }
 },

 activate: function(draggable) {
 if(draggable.options.delay) {
 this._timeout = setTimeout(function() {
 Draggables._timeout = null;
 window.focus();
 Draggables.activeDraggable = draggable;
 }.bind(this), draggable.options.delay);
 } else {
 window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
 this.activeDraggable = draggable;
 }
 },

 deactivate: function() {
 this.activeDraggable = null;
 },

 updateDrag: function(event) {
 if(!this.activeDraggable) return;
 var pointer = [Event.pointerX(event), Event.pointerY(event)];
 // Mozilla-based browsers fire successive mousemove events with
 // the same coordinates, prevent needless redrawing (moz bug?)
 if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
 this._lastPointer = pointer;

 this.activeDraggable.updateDrag(event, pointer);
 },

 endDrag: function(event) {
 if(this._timeout) {
 clearTimeout(this._timeout);
 this._timeout = null;
 }
 if(!this.activeDraggable) return;
 this._lastPointer = null;
 this.activeDraggable.endDrag(event);
 this.activeDraggable = null;
 },

 keyPress: function(event) {
 if(this.activeDraggable)
 this.activeDraggable.keyPress(event);
 },

 addObserver: function(observer) {
 this.observers.push(observer);
 this._cacheObserverCallbacks();
 },

 removeObserver: function(element) { // element instead of observer fixes mem leaks
 this.observers = this.observers.reject( function(o) { return o.element==element });
 this._cacheObserverCallbacks();
 },

 notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag'
 if(this[eventName+'Count'] > 0)
 this.observers.each( function(o) {
 if(o[eventName]) o[eventName](eventName, draggable, event);
 });
 if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
 },

 _cacheObserverCallbacks: function() {
 ['onStart','onEnd','onDrag'].each( function(eventName) {
 Draggables[eventName+'Count'] = Draggables.observers.select(
 function(o) { return o[eventName]; }
 ).length;
 });
 }
}

/*--------------------------------------------------------------------------*/

var Draggable = Class.create();
Draggable._dragging = {};

Draggable.prototype = {
 initialize: function(element) {
 var defaults = {
 handle: false,
 reverteffect: function(element, top_offset, left_offset) {
 var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
 new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
 queue: {scope:'_draggable', position:'end'}
 });
 },
 endeffect: function(element) {
 var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0;
 new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
 queue: {scope:'_draggable', position:'end'},
 afterFinish: function(){
 Draggable._dragging[element] = false
 }
 });
 },
 zindex: 1000,
 revert: false,
 quiet: false,
 scroll: false,
 scrollSensitivity: 20,
 scrollSpeed: 15,
 snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] }
 delay: 0
 };

 if(!arguments[1] || typeof arguments[1].endeffect == 'undefined')
 Object.extend(defaults, {
 starteffect: function(element) {
 element._opacity = Element.getOpacity(element);
 Draggable._dragging[element] = true;
 new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
 }
 });

 var options = Object.extend(defaults, arguments[1] || {});

 this.element = $(element);

 if(options.handle && (typeof options.handle == 'string'))
 this.handle = this.element.down('.'+options.handle, 0);

 if(!this.handle) this.handle = $(options.handle);
 if(!this.handle) this.handle = this.element;

 if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
 options.scroll = $(options.scroll);
 this._isScrollChild = Element.childOf(this.element, options.scroll);
 }

 Element.makePositioned(this.element); // fix IE

 this.delta = this.currentDelta();
 this.options = options;
 this.dragging = false;

 this.eventMouseDown = this.initDrag.bindAsEventListener(this);
 Event.observe(this.handle, "mousedown", this.eventMouseDown);

 Draggables.register(this);
 },

 destroy: function() {
 Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
 Draggables.unregister(this);
 },

 currentDelta: function() {
 return([
 parseInt(Element.getStyle(this.element,'left') || '0'),
 parseInt(Element.getStyle(this.element,'top') || '0')]);
 },

 initDrag: function(event) {
 if(typeof Draggable._dragging[this.element] != 'undefined' &&
 Draggable._dragging[this.element]) return;
 if(Event.isLeftClick(event)) {
 // abort on form elements, fixes a Firefox issue
 var src = Event.element(event);
 if((tag_name = src.tagName.toUpperCase()) && (
 tag_name=='INPUT' ||
 tag_name=='SELECT' ||
 tag_name=='OPTION' ||
 tag_name=='BUTTON' ||
 tag_name=='TEXTAREA')) return;

 var pointer = [Event.pointerX(event), Event.pointerY(event)];
 var pos = Position.cumulativeOffset(this.element);
 this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });

 Draggables.activate(this);
 Event.stop(event);
 }
 },

 startDrag: function(event) {
 this.dragging = true;

 if(this.options.zindex) {
 this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
 this.element.style.zIndex = this.options.zindex;
 }

 if(this.options.ghosting) {
 this._clone = this.element.cloneNode(true);
 Position.absolutize(this.element);
 this.element.parentNode.insertBefore(this._clone, this.element);
 }

 if(this.options.scroll) {
 if (this.options.scroll == window) {
 var where = this._getWindowScroll(this.options.scroll);
 this.originalScrollLeft = where.left;
 this.originalScrollTop = where.top;
 } else {
 this.originalScrollLeft = this.options.scroll.scrollLeft;
 this.originalScrollTop = this.options.scroll.scrollTop;
 }
 }

 Draggables.notify('onStart', this, event);

 if(this.options.starteffect) this.options.starteffect(this.element);
 },

 updateDrag: function(event, pointer) {
 if(!this.dragging) this.startDrag(event);

 if(!this.options.quiet){
 Position.prepare();
 Droppables.show(pointer, this.element);
 }

 Draggables.notify('onDrag', this, event);

 this.draw(pointer);
 if(this.options.change) this.options.change(this);

 if(this.options.scroll) {
 this.stopScrolling();

 var p;
 if (this.options.scroll == window) {
 with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
 } else {
 p = Position.page(this.options.scroll);
 p[0] += this.options.scroll.scrollLeft + Position.deltaX;
 p[1] += this.options.scroll.scrollTop + Position.deltaY;
 p.push(p[0]+this.options.scroll.offsetWidth);
 p.push(p[1]+this.options.scroll.offsetHeight);
 }
 var speed = [0,0];
 if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
 if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
 if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
 if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
 this.startScrolling(speed);
 }

 // fix AppleWebKit rendering
 if(Prototype.Browser.WebKit) window.scrollBy(0,0);

 Event.stop(event);
 },

 finishDrag: function(event, success) {
 this.dragging = false;

 if(this.options.quiet){
 Position.prepare();
 var pointer = [Event.pointerX(event), Event.pointerY(event)];
 Droppables.show(pointer, this.element);
 }

 if(this.options.ghosting) {
 Position.relativize(this.element);
 Element.remove(this._clone);
 this._clone = null;
 }

 var dropped = false;
 if(success) {
 dropped = Droppables.fire(event, this.element);
 if (!dropped) dropped = false;
 }
 if(dropped && this.options.onDropped) this.options.onDropped(this.element);
 Draggables.notify('onEnd', this, event);

 var revert = this.options.revert;
 if(revert && typeof revert == 'function') revert = revert(this.element);

 var d = this.currentDelta();
 if(revert && this.options.reverteffect) {
 if (dropped == 0 || revert != 'failure')
 this.options.reverteffect(this.element,
 d[1]-this.delta[1], d[0]-this.delta[0]);
 } else {
 this.delta = d;
 }

 if(this.options.zindex)
 this.element.style.zIndex = this.originalZ;

 if(this.options.endeffect)
 this.options.endeffect(this.element);

 Draggables.deactivate(this);
 Droppables.reset();
 },

 keyPress: function(event) {
 if(event.keyCode!=Event.KEY_ESC) return;
 this.finishDrag(event, false);
 Event.stop(event);
 },

 endDrag: function(event) {
 if(!this.dragging) return;
 this.stopScrolling();
 this.finishDrag(event, true);
 Event.stop(event);
 },

 draw: function(point) {
 var pos = Position.cumulativeOffset(this.element);
 if(this.options.ghosting) {
 var r = Position.realOffset(this.element);
 pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
 }

 var d = this.currentDelta();
 pos[0] -= d[0]; pos[1] -= d[1];

 if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
 pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
 pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
 }

 var p = [0,1].map(function(i){
 return (point[i]-pos[i]-this.offset[i])
 }.bind(this));

 if(this.options.snap) {
 if(typeof this.options.snap == 'function') {
 p = this.options.snap(p[0],p[1],this);
 } else {
 if(this.options.snap instanceof Array) {
 p = p.map( function(v, i) {
 return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
 } else {
 p = p.map( function(v) {
 return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
 }
 }}

 var style = this.element.style;
 if((!this.options.constraint) || (this.options.constraint=='horizontal'))
 style.left = p[0] + "px";
 if((!this.options.constraint) || (this.options.constraint=='vertical'))
 style.top = p[1] + "px";

 if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
 },

 stopScrolling: function() {
 if(this.scrollInterval) {
 clearInterval(this.scrollInterval);
 this.scrollInterval = null;
 Draggables._lastScrollPointer = null;
 }
 },

 startScrolling: function(speed) {
 if(!(speed[0] || speed[1])) return;
 this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
 this.lastScrolled = new Date();
 this.scrollInterval = setInterval(this.scroll.bind(this), 10);
 },

 scroll: function() {
 var current = new Date();
 var delta = current - this.lastScrolled;
 this.lastScrolled = current;
 if(this.options.scroll == window) {
 with (this._getWindowScroll(this.options.scroll)) {
 if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
 var d = delta / 1000;
 this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
 }
 }
 } else {
 this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
 this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000;
 }

 Position.prepare();
 Droppables.show(Draggables._lastPointer, this.element);
 Draggables.notify('onDrag', this);
 if (this._isScrollChild) {
 Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
 Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
 Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
 if (Draggables._lastScrollPointer[0] < 0)
 Draggables._lastScrollPointer[0] = 0;
 if (Draggables._lastScrollPointer[1] < 0)
 Draggables._lastScrollPointer[1] = 0;
 this.draw(Draggables._lastScrollPointer);
 }

 if(this.options.change) this.options.change(this);
 },

 _getWindowScroll: function(w) {
 var T, L, W, H;
 with (w.document) {
 if (w.document.documentElement && documentElement.scrollTop) {
 T = documentElement.scrollTop;
 L = documentElement.scrollLeft;
 } else if (w.document.body) {
 T = body.scrollTop;
 L = body.scrollLeft;
 }
 if (w.innerWidth) {
 W = w.innerWidth;
 H = w.innerHeight;
 } else if (w.document.documentElement && documentElement.clientWidth) {
 W = documentElement.clientWidth;
 H = documentElement.clientHeight;
 } else {
 W = body.offsetWidth;
 H = body.offsetHeight
 }
 }
 return { top: T, left: L, width: W, height: H };
 }
}

/*--------------------------------------------------------------------------*/

var SortableObserver = Class.create();
SortableObserver.prototype = {
 initialize: function(element, observer) {
 this.element = $(element);
 this.observer = observer;
 this.lastValue = Sortable.serialize(this.element);
 },

 onStart: function() {
 this.lastValue = Sortable.serialize(this.element);
 },

 onEnd: function() {
 Sortable.unmark();
 if(this.lastValue != Sortable.serialize(this.element))
 this.observer(this.element)
 }
}

var Sortable = {
 SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,

 sortables: {},

 _findRootElement: function(element) {
 while (element.tagName.toUpperCase() != "BODY") {
 if(element.id && Sortable.sortables[element.id]) return element;
 element = element.parentNode;
 }
 },

 options: function(element) {
 element = Sortable._findRootElement($(element));
 if(!element) return;
 return Sortable.sortables[element.id];
 },

 destroy: function(element){
 var s = Sortable.options(element);

 if(s) {
 Draggables.removeObserver(s.element);
 s.droppables.each(function(d){ Droppables.remove(d) });
 s.draggables.invoke('destroy');

 delete Sortable.sortables[s.element.id];
 }
 },

 create: function(element) {
 element = $(element);
 var options = Object.extend({
 element: element,
 tag: 'li', // assumes li children, override with tag: 'tagname'
 dropOnEmpty: false,
 tree: false,
 treeTag: 'ul',
 overlap: 'vertical', // one of 'vertical', 'horizontal'
 constraint: 'vertical', // one of 'vertical', 'horizontal', false
 containment: element, // also takes array of elements (or id's); or false
 handle: false, // or a CSS class
 only: false,
 delay: 0,
 hoverclass: null,
 ghosting: false,
 quiet: false,
 scroll: false,
 scrollSensitivity: 20,
 scrollSpeed: 15,
 format: this.SERIALIZE_RULE,

 // these take arrays of elements or ids and can be
 // used for better initialization performance
 elements: false,
 handles: false,

 onChange: Prototype.emptyFunction,
 onUpdate: Prototype.emptyFunction
 }, arguments[1] || {});

 // clear any old sortable with same element
 this.destroy(element);

 // build options for the draggables
 var options_for_draggable = {
 revert: true,
 quiet: options.quiet,
 scroll: options.scroll,
 scrollSpeed: options.scrollSpeed,
 scrollSensitivity: options.scrollSensitivity,
 delay: options.delay,
 ghosting: options.ghosting,
 constraint: options.constraint,
 handle: options.handle };

 if(options.starteffect)
 options_for_draggable.starteffect = options.starteffect;

 if(options.reverteffect)
 options_for_draggable.reverteffect = options.reverteffect;
 else
 if(options.ghosting) options_for_draggable.reverteffect = function(element) {
 element.style.top = 0;
 element.style.left = 0;
 };

 if(options.endeffect)
 options_for_draggable.endeffect = options.endeffect;

 if(options.zindex)
 options_for_draggable.zindex = options.zindex;

 // build options for the droppables
 var options_for_droppable = {
 overlap: options.overlap,
 containment: options.containment,
 tree: options.tree,
 hoverclass: options.hoverclass,
 onHover: Sortable.onHover
 }

 var options_for_tree = {
 onHover: Sortable.onEmptyHover,
 overlap: options.overlap,
 containment: options.containment,
 hoverclass: options.hoverclass
 }

 // fix for gecko engine
 Element.cleanWhitespace(element);

 options.draggables = [];
 options.droppables = [];

 // drop on empty handling
 if(options.dropOnEmpty || options.tree) {
 Droppables.add(element, options_for_tree);
 options.droppables.push(element);
 }

 (options.elements || this.findElements(element, options) || []).each( function(e,i) {
 var handle = options.handles ? $(options.handles[i]) :
 (options.handle ? $(e).getElementsByClassName(options.handle)[0] : e);
 options.draggables.push(
 new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
 Droppables.add(e, options_for_droppable);
 if(options.tree) e.treeNode = element;
 options.droppables.push(e);
 });

 if(options.tree) {
 (Sortable.findTreeElements(element, options) || []).each( function(e) {
 Droppables.add(e, options_for_tree);
 e.treeNode = element;
 options.droppables.push(e);
 });
 }

 // keep reference
 this.sortables[element.id] = options;

 // for onupdate
 Draggables.addObserver(new SortableObserver(element, options.onUpdate));

 },

 // return all suitable-for-sortable elements in a guaranteed order
 findElements: function(element, options) {
 return Element.findChildren(
 element, options.only, options.tree ? true : false, options.tag);
 },

 findTreeElements: function(element, options) {
 return Element.findChildren(
 element, options.only, options.tree ? true : false, options.treeTag);
 },

 onHover: function(element, dropon, overlap) {
 if(Element.isParent(dropon, element)) return;

 if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
 return;
 } else if(overlap>0.5) {
 Sortable.mark(dropon, 'before');
 if(dropon.previousSibling != element) {
 var oldParentNode = element.parentNode;
 element.style.visibility = "hidden"; // fix gecko rendering
 dropon.parentNode.insertBefore(element, dropon);
 if(dropon.parentNode!=oldParentNode)
 Sortable.options(oldParentNode).onChange(element);
 Sortable.options(dropon.parentNode).onChange(element);
 }
 } else {
 Sortable.mark(dropon, 'after');
 var nextElement = dropon.nextSibling || null;
 if(nextElement != element) {
 var oldParentNode = element.parentNode;
 element.style.visibility = "hidden"; // fix gecko rendering
 dropon.parentNode.insertBefore(element, nextElement);
 if(dropon.parentNode!=oldParentNode)
 Sortable.options(oldParentNode).onChange(element);
 Sortable.options(dropon.parentNode).onChange(element);
 }
 }
 },

 onEmptyHover: function(element, dropon, overlap) {
 var oldParentNode = element.parentNode;
 var droponOptions = Sortable.options(dropon);

 if(!Element.isParent(dropon, element)) {
 var index;

 var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
 var child = null;

 if(children) {
 var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);

 for (index = 0; index < children.length; index += 1) {
 if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
 offset -= Element.offsetSize (children[index], droponOptions.overlap);
 } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
 child = index + 1 < children.length ? children[index + 1] : null;
 break;
 } else {
 child = children[index];
 break;
 }
 }
 }

 dropon.insertBefore(element, child);

 Sortable.options(oldParentNode).onChange(element);
 droponOptions.onChange(element);
 }
 },

 unmark: function() {
 if(Sortable._marker) Sortable._marker.hide();
 },

 mark: function(dropon, position) {
 // mark on ghosting only
 var sortable = Sortable.options(dropon.parentNode);
 if(sortable && !sortable.ghosting) return;

 if(!Sortable._marker) {
 Sortable._marker =
 ($('dropmarker') || Element.extend(document.createElement('DIV'))).
 hide().addClassName('dropmarker').setStyle({position:'absolute'});
 document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
 }
 var offsets = Position.cumulativeOffset(dropon);
 Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});

 if(position=='after')
 if(sortable.overlap == 'horizontal')
 Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
 else
 Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});

 Sortable._marker.show();
 },

 _tree: function(element, options, parent) {
 var children = Sortable.findElements(element, options) || [];

 for (var i = 0; i < children.length; ++i) {
 var match = children[i].id.match(options.format);

 if (!match) continue;

 var child = {
 id: encodeURIComponent(match ? match[1] : null),
 element: element,
 parent: parent,
 children: [],
 position: parent.children.length,
 container: $(children[i]).down(options.treeTag)
 }

 /* Get the element containing the children and recurse over it */
 if (child.container)
 this._tree(child.container, options, child)

 parent.children.push (child);
 }

 return parent;
 },

 tree: function(element) {
 element = $(element);
 var sortableOptions = this.options(element);
 var options = Object.extend({
 tag: sortableOptions.tag,
 treeTag: sortableOptions.treeTag,
 only: sortableOptions.only,
 name: element.id,
 format: sortableOptions.format
 }, arguments[1] || {});

 var root = {
 id: null,
 parent: null,
 children: [],
 container: element,
 position: 0
 }

 return Sortable._tree(element, options, root);
 },

 /* Construct a [i] index for a particular node */
 _constructIndex: function(node) {
 var index = '';
 do {
 if (node.id) index = '[' + node.position + ']' + index;
 } while ((node = node.parent) != null);
 return index;
 },

 sequence: function(element) {
 element = $(element);
 var options = Object.extend(this.options(element), arguments[1] || {});

 return $(this.findElements(element, options) || []).map( function(item) {
 return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
 });
 },

 setSequence: function(element, new_sequence) {
 element = $(element);
 var options = Object.extend(this.options(element), arguments[2] || {});

 var nodeMap = {};
 this.findElements(element, options).each( function(n) {
 if (n.id.match(options.format))
 nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
 n.parentNode.removeChild(n);
 });

 new_sequence.each(function(ident) {
 var n = nodeMap[ident];
 if (n) {
 n[1].appendChild(n[0]);
 delete nodeMap[ident];
 }
 });
 },

 serialize: function(element) {
 element = $(element);
 var options = Object.extend(Sortable.options(element), arguments[1] || {});
 var name = encodeURIComponent(
 (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);

 if (options.tree) {
 return Sortable.tree(element, arguments[1]).children.map( function (item) {
 return [name + Sortable._constructIndex(item) + "[id]=" +
 encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
 }).flatten().join('&');
 } else {
 return Sortable.sequence(element, arguments[1]).map( function(item) {
 return name + "[]=" + encodeURIComponent(item);
 }).join('&');
 }
 }
}

// Returns true if child is contained within element
Element.isParent = function(child, element) {
 if (!child.parentNode || child == element) return false;
 if (child.parentNode == element) return true;
 return Element.isParent(child.parentNode, element);
}

Element.findChildren = function(element, only, recursive, tagName) {
 if(!element.hasChildNodes()) return null;
 tagName = tagName.toUpperCase();
 if(only) only = [only].flatten();
 var elements = [];
 $A(element.childNodes).each( function(e) {
 if(e.tagName && e.tagName.toUpperCase()==tagName &&
 (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
 elements.push(e);
 if(recursive) {
 var grandchildren = Element.findChildren(e, only, recursive, tagName);
 if(grandchildren) elements.push(grandchildren);
 }
 });

 return (elements.length>0 ? elements.flatten() : []);
}

Element.offsetSize = function (element, type) {
 return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
}

// script.aculo.us controls.js v1.7.1_beta3, Fri May 25 17:19:41 +0200 2007

// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
// (c) 2005-2007 Jon Tirsen (http://www.tirsen.com)
// Contributors:
// Richard Livsey
// Rahul Bhargava
// Rob Wills
// 
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/

// Autocompleter.Base handles all the autocompletion functionality 
// that's independent of the data source for autocompletion. This
// includes drawing the autocompletion menu, observing keyboard
// and mouse events, and similar.
//
// Specific autocompleters need to provide, at the very least, 
// a getUpdatedChoices function that will be invoked every time
// the text inside the monitored textbox changes. This method 
// should get the text for which to provide autocompletion by
// invoking this.getToken(), NOT by directly accessing
// this.element.value. This is to allow incremental tokenized
// autocompletion. Specific auto-completion logic (AJAX, etc)
// belongs in getUpdatedChoices.
//
// Tokenized incremental autocompletion is enabled automatically
// when an autocompleter is instantiated with the 'tokens' option
// in the options parameter, e.g.:
// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
// will incrementally autocomplete with a comma as the token.
// Additionally, ',' in the above example can be replaced with
// a token array, e.g. { tokens: [',', '\n'] } which
// enables autocompletion on multiple tokens. This is most 
// useful when one of the tokens is \n (a newline), as it 
// allows smart autocompletion after linebreaks.

if(typeof Effect == 'undefined')
 throw("controls.js requires including script.aculo.us' effects.js library");

var Autocompleter = {}
Autocompleter.Base = function() {};
Autocompleter.Base.prototype = {
 baseInitialize: function(element, update, options) {
 element = $(element)
 this.element = element; 
 this.update = $(update); 
 this.hasFocus = false; 
 this.changed = false; 
 this.active = false; 
 this.index = 0; 
 this.entryCount = 0;

 if(this.setOptions)
 this.setOptions(options);
 else
 this.options = options || {};

 this.options.paramName = this.options.paramName || this.element.name;
 this.options.tokens = this.options.tokens || [];
 this.options.frequency = this.options.frequency || 0.4;
 this.options.minChars = this.options.minChars || 1;
 this.options.onShow = this.options.onShow || 
 function(element, update){ 
 if(!update.style.position || update.style.position=='absolute') {
 update.style.position = 'absolute';
 Position.clone(element, update, {
 setHeight: false, 
 offsetTop: element.offsetHeight
 });
 }
 Effect.Appear(update,{duration:0.15});
 };
 this.options.onHide = this.options.onHide || 
 function(element, update){ new Effect.Fade(update,{duration:0.15}) };

 if(typeof(this.options.tokens) == 'string') 
 this.options.tokens = new Array(this.options.tokens);

 this.observer = null;
 
 this.element.setAttribute('autocomplete','off');

 Element.hide(this.update);

 Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
 Event.observe(this.element, 'keypress', this.onKeyPress.bindAsEventListener(this));

 // Turn autocomplete back on when the user leaves the page, so that the
 // field's value will be remembered on Mozilla-based browsers.
 Event.observe(window, 'beforeunload', function(){ 
 element.setAttribute('autocomplete', 'on'); 
 });
 },

 show: function() {
 if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
 if(!this.iefix && 
 (Prototype.Browser.IE) &&
 (Element.getStyle(this.update, 'position')=='absolute')) {
 new Insertion.After(this.update, 
 '<iframe id="' + this.update.id + '_iefix" '+
 'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
 'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
 this.iefix = $(this.update.id+'_iefix');
 }
 if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
 },
 
 fixIEOverlapping: function() {
 Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
 this.iefix.style.zIndex = 1;
 this.update.style.zIndex = 2;
 Element.show(this.iefix);
 },

 hide: function() {
 this.stopIndicator();
 if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
 if(this.iefix) Element.hide(this.iefix);
 },

 startIndicator: function() {
 if(this.options.indicator) Element.show(this.options.indicator);
 },

 stopIndicator: function() {
 if(this.options.indicator) Element.hide(this.options.indicator);
 },

 onKeyPress: function(event) {
 if(this.active)
 switch(event.keyCode) {
 case Event.KEY_TAB:
 case Event.KEY_RETURN:
 this.selectEntry();
 Event.stop(event);
 case Event.KEY_ESC:
 this.hide();
 this.active = false;
 Event.stop(event);
 return;
 case Event.KEY_LEFT:
 case Event.KEY_RIGHT:
 return;
 case Event.KEY_UP:
 this.markPrevious();
 this.render();
 if(Prototype.Browser.WebKit) Event.stop(event);
 return;
 case Event.KEY_DOWN:
 this.markNext();
 this.render();
 if(Prototype.Browser.WebKit) Event.stop(event);
 return;
 }
 else 
 if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || 
 (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;

 this.changed = true;
 this.hasFocus = true;

 if(this.observer) clearTimeout(this.observer);
 this.observer = 
 setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
 },

 activate: function() {
 this.changed = false;
 this.hasFocus = true;
 this.getUpdatedChoices();
 },

 onHover: function(event) {
 var element = Event.findElement(event, 'LI');
 if(this.index != element.autocompleteIndex) 
 {
 this.index = element.autocompleteIndex;
 this.render();
 }
 Event.stop(event);
 },
 
 onClick: function(event) {
 var element = Event.findElement(event, 'LI');
 this.index = element.autocompleteIndex;
 this.selectEntry();
 this.hide();
 },
 
 onBlur: function(event) {
 // needed to make click events working
 setTimeout(this.hide.bind(this), 250);
 this.hasFocus = false;
 this.active = false; 
 }, 
 
 render: function() {
 if(this.entryCount > 0) {
 for (var i = 0; i < this.entryCount; i++)
 this.index==i ? 
 Element.addClassName(this.getEntry(i),"selected") : 
 Element.removeClassName(this.getEntry(i),"selected");
 if(this.hasFocus) { 
 this.show();
 this.active = true;
 }
 } else {
 this.active = false;
 this.hide();
 }
 },
 
 markPrevious: function() {
 if(this.index > 0) this.index--
 else this.index = this.entryCount-1;
 this.getEntry(this.index).scrollIntoView(true);
 },
 
 markNext: function() {
 if(this.index < this.entryCount-1) this.index++
 else this.index = 0;
 this.getEntry(this.index).scrollIntoView(false);
 },
 
 getEntry: function(index) {
 return this.update.firstChild.childNodes[index];
 },
 
 getCurrentEntry: function() {
 return this.getEntry(this.index);
 },
 
 selectEntry: function() {
 this.active = false;
 this.updateElement(this.getCurrentEntry());
 },

 updateElement: function(selectedElement) {
 if (this.options.updateElement) {
 this.options.updateElement(selectedElement);
 return;
 }
 var value = '';
 if (this.options.select) {
 var nodes = document.getElementsByClassName(this.options.select, selectedElement) || [];
 if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
 } else
 value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
 
 var lastTokenPos = this.findLastToken();
 if (lastTokenPos != -1) {
 var newValue = this.element.value.substr(0, lastTokenPos + 1);
 var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/);
 if (whitespace)
 newValue += whitespace[0];
 this.element.value = newValue + value;
 } else {
 this.element.value = value;
 }
 this.element.focus();
 
 if (this.options.afterUpdateElement)
 this.options.afterUpdateElement(this.element, selectedElement);
 },

 updateChoices: function(choices) {
 if(!this.changed && this.hasFocus) {
 this.update.innerHTML = choices;
 Element.cleanWhitespace(this.update);
 Element.cleanWhitespace(this.update.down());

 if(this.update.firstChild && this.update.down().childNodes) {
 this.entryCount = 
 this.update.down().childNodes.length;
 for (var i = 0; i < this.entryCount; i++) {
 var entry = this.getEntry(i);
 entry.autocompleteIndex = i;
 this.addObservers(entry);
 }
 } else { 
 this.entryCount = 0;
 }

 this.stopIndicator();
 this.index = 0;
 
 if(this.entryCount==1 && this.options.autoSelect) {
 this.selectEntry();
 this.hide();
 } else {
 this.render();
 }
 }
 },

 addObservers: function(element) {
 Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
 Event.observe(element, "click", this.onClick.bindAsEventListener(this));
 },

 onObserverEvent: function() {
 this.changed = false; 
 if(this.getToken().length>=this.options.minChars) {
 this.getUpdatedChoices();
 } else {
 this.active = false;
 this.hide();
 }
 },

 getToken: function() {
 var tokenPos = this.findLastToken();
 if (tokenPos != -1)
 var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,'');
 else
 var ret = this.element.value;

 return /\n/.test(ret) ? '' : ret;
 },

 findLastToken: function() {
 var lastTokenPos = -1;

 for (var i=0; i<this.options.tokens.length; i++) {
 var thisTokenPos = this.element.value.lastIndexOf(this.options.tokens[i]);
 if (thisTokenPos > lastTokenPos)
 lastTokenPos = thisTokenPos;
 }
 return lastTokenPos;
 }
}

Ajax.Autocompleter = Class.create();
Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), {
 initialize: function(element, update, url, options) {
 this.baseInitialize(element, update, options);
 this.options.asynchronous = true;
 this.options.onComplete = this.onComplete.bind(this);
 this.options.defaultParams = this.options.parameters || null;
 this.url = url;
 },

 getUpdatedChoices: function() {
 this.startIndicator();
 
 var entry = encodeURIComponent(this.options.paramName) + '=' + 
 encodeURIComponent(this.getToken());

 this.options.parameters = this.options.callback ?
 this.options.callback(this.element, entry) : entry;

 if(this.options.defaultParams) 
 this.options.parameters += '&' + this.options.defaultParams;
 
 new Ajax.Request(this.url, this.options);
 },

 onComplete: function(request) {
 this.updateChoices(request.responseText);
 }

});

// The local array autocompleter. Used when you'd prefer to
// inject an array of autocompletion options into the page, rather
// than sending out Ajax queries, which can be quite slow sometimes.
//
// The constructor takes four parameters. The first two are, as usual,
// the id of the monitored textbox, and id of the autocompletion menu.
// The third is the array you want to autocomplete from, and the fourth
// is the options block.
//
// Extra local autocompletion options:
// - choices - How many autocompletion choices to offer
//
// - partialSearch - If false, the autocompleter will match entered
// text only at the beginning of strings in the 
// autocomplete array. Defaults to true, which will
// match text at the beginning of any *word* in the
// strings in the autocomplete array. If you want to
// search anywhere in the string, additionally set
// the option fullSearch to true (default: off).
//
// - fullSsearch - Search anywhere in autocomplete array strings.
//
// - partialChars - How many characters to enter before triggering
// a partial match (unlike minChars, which defines
// how many characters are required to do any match
// at all). Defaults to 2.
//
// - ignoreCase - Whether to ignore case when autocompleting.
// Defaults to true.
//
// It's possible to pass in a custom function as the 'selector' 
// option, if you prefer to write your own autocompletion logic.
// In that case, the other options above will not apply unless
// you support them.

Autocompleter.Local = Class.create();
Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
 initialize: function(element, update, array, options) {
 this.baseInitialize(element, update, options);
 this.options.array = array;
 },

 getUpdatedChoices: function() {
 this.updateChoices(this.options.selector(this));
 },

 setOptions: function(options) {
 this.options = Object.extend({
 choices: 10,
 partialSearch: true,
 partialChars: 2,
 ignoreCase: true,
 fullSearch: false,
 selector: function(instance) {
 var ret = []; // Beginning matches
 var partial = []; // Inside matches
 var entry = instance.getToken();
 var count = 0;

 for (var i = 0; i < instance.options.array.length && 
 ret.length < instance.options.choices ; i++) { 

 var elem = instance.options.array[i];
 var foundPos = instance.options.ignoreCase ? 
 elem.toLowerCase().indexOf(entry.toLowerCase()) : 
 elem.indexOf(entry);

 while (foundPos != -1) {
 if (foundPos == 0 && elem.length != entry.length) { 
 ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" + 
 elem.substr(entry.length) + "</li>");
 break;
 } else if (entry.length >= instance.options.partialChars && 
 instance.options.partialSearch && foundPos != -1) {
 if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
 partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
 elem.substr(foundPos, entry.length) + "</strong>" + elem.substr(
 foundPos + entry.length) + "</li>");
 break;
 }
 }

 foundPos = instance.options.ignoreCase ? 
 elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : 
 elem.indexOf(entry, foundPos + 1);

 }
 }
 if (partial.length)
 ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
 return "<ul>" + ret.join('') + "</ul>";
 }
 }, options || {});
 }
});

// AJAX in-place editor
//
// see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor

// Use this if you notice weird scrolling problems on some browsers,
// the DOM might be a bit confused when this gets called so do this
// waits 1 ms (with setTimeout) until it does the activation
Field.scrollFreeActivate = function(field) {
 setTimeout(function() {
 Field.activate(field);
 }, 1);
}

Ajax.InPlaceEditor = Class.create();
Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99";
Ajax.InPlaceEditor.prototype = {
 initialize: function(element, url, options) {
 this.url = url;
 this.element = $(element);

 this.options = Object.extend({
 paramName: "value",
 okButton: true,
 okLink: false,
 okText: "ok",
 cancelButton: false,
 cancelLink: true,
 cancelText: "cancel",
 textBeforeControls: '',
 textBetweenControls: '',
 textAfterControls: '',
 savingText: "Saving...",
 clickToEditText: "Click to edit",
 okText: "ok",
 rows: 1,
 onComplete: function(transport, element) {
 new Effect.Highlight(element, {startcolor: this.options.highlightcolor});
 },
 onFailure: function(transport) {
 alert("Error communicating with the server: " + transport.responseText.stripTags());
 },
 callback: function(form) {
 return Form.serialize(form);
 },
 handleLineBreaks: true,
 loadingText: 'Loading...',
 savingClassName: 'inplaceeditor-saving',
 loadingClassName: 'inplaceeditor-loading',
 formClassName: 'inplaceeditor-form',
 highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
 highlightendcolor: "#FFFFFF",
 externalControl: null,
 submitOnBlur: false,
 ajaxOptions: {},
 evalScripts: false
 }, options || {});

 if(!this.options.formId && this.element.id) {
 this.options.formId = this.element.id + "-inplaceeditor";
 if ($(this.options.formId)) {
 // there's already a form with that name, don't specify an id
 this.options.formId = null;
 }
 }
 
 if (this.options.externalControl) {
 this.options.externalControl = $(this.options.externalControl);
 }
 
 this.originalBackground = Element.getStyle(this.element, 'background-color');
 if (!this.originalBackground) {
 this.originalBackground = "transparent";
 }
 
 this.element.title = this.options.clickToEditText;
 
 this.onclickListener = this.enterEditMode.bindAsEventListener(this);
 this.mouseoverListener = this.enterHover.bindAsEventListener(this);
 this.mouseoutListener = this.leaveHover.bindAsEventListener(this);
 Event.observe(this.element, 'click', this.onclickListener);
 Event.observe(this.element, 'mouseover', this.mouseoverListener);
 Event.observe(this.element, 'mouseout', this.mouseoutListener);
 if (this.options.externalControl) {
 Event.observe(this.options.externalControl, 'click', this.onclickListener);
 Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener);
 Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener);
 }
 },
 enterEditMode: function(evt) {
 if (this.saving) return;
 if (this.editing) return;
 this.editing = true;
 this.onEnterEditMode();
 if (this.options.externalControl) {
 Element.hide(this.options.externalControl);
 }
 Element.hide(this.element);
 this.createForm();
 this.element.parentNode.insertBefore(this.form, this.element);
 if (!this.options.loadTextURL) Field.scrollFreeActivate(this.editField);
 // stop the event to avoid a page refresh in Safari
 if (evt) {
 Event.stop(evt);
 }
 return false;
 },
 createForm: function() {
 this.form = document.createElement("form");
 this.form.id = this.options.formId;
 Element.addClassName(this.form, this.options.formClassName)
 this.form.onsubmit = this.onSubmit.bind(this);

 this.createEditField();

 if (this.options.textarea) {
 var br = document.createElement("br");
 this.form.appendChild(br);
 }
 
 if (this.options.textBeforeControls)
 this.form.appendChild(document.createTextNode(this.options.textBeforeControls));

 if (this.options.okButton) {
 var okButton = document.createElement("input");
 okButton.type = "submit";
 okButton.value = this.options.okText;
 okButton.className = 'editor_ok_button';
 this.form.appendChild(okButton);
 }
 
 if (this.options.okLink) {
 var okLink = document.createElement("a");
 okLink.href = "#";
 okLink.appendChild(document.createTextNode(this.options.okText));
 okLink.onclick = this.onSubmit.bind(this);
 okLink.className = 'editor_ok_link';
 this.form.appendChild(okLink);
 }
 
 if (this.options.textBetweenControls && 
 (this.options.okLink || this.options.okButton) && 
 (this.options.cancelLink || this.options.cancelButton))
 this.form.appendChild(document.createTextNode(this.options.textBetweenControls));
 
 if (this.options.cancelButton) {
 var cancelButton = document.createElement("input");
 cancelButton.type = "submit";
 cancelButton.value = this.options.cancelText;
 cancelButton.onclick = this.onclickCancel.bind(this);
 cancelButton.className = 'editor_cancel_button';
 this.form.appendChild(cancelButton);
 }

 if (this.options.cancelLink) {
 var cancelLink = document.createElement("a");
 cancelLink.href = "#";
 cancelLink.appendChild(document.createTextNode(this.options.cancelText));
 cancelLink.onclick = this.onclickCancel.bind(this);
 cancelLink.className = 'editor_cancel editor_cancel_link'; 
 this.form.appendChild(cancelLink);
 }
 
 if (this.options.textAfterControls)
 this.form.appendChild(document.createTextNode(this.options.textAfterControls));
 },
 hasHTMLLineBreaks: function(string) {
 if (!this.options.handleLineBreaks) return false;
 return string.match(/<br/i) || string.match(/<p>/i);
 },
 convertHTMLLineBreaks: function(string) {
 return string.replace(/<br>/gi, "\n").replace(/<br\/>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<p>/gi, "");
 },
 createEditField: function() {
 var text;
 if(this.options.loadTextURL) {
 text = this.options.loadingText;
 } else {
 text = this.getText();
 }

 var obj = this;
 
 if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
 this.options.textarea = false;
 var textField = document.createElement("input");
 textField.obj = this;
 textField.type = "text";
 textField.name = this.options.paramName;
 textField.value = text;
 textField.style.backgroundColor = this.options.highlightcolor;
 textField.className = 'editor_field';
 var size = this.options.size || this.options.cols || 0;
 if (size != 0) textField.size = size;
 if (this.options.submitOnBlur)
 textField.onblur = this.onSubmit.bind(this);
 this.editField = textField;
 } else {
 this.options.textarea = true;
 var textArea = document.createElement("textarea");
 textArea.obj = this;
 textArea.name = this.options.paramName;
 textArea.value = this.convertHTMLLineBreaks(text);
 textArea.rows = this.options.rows;
 textArea.cols = this.options.cols || 40;
 textArea.className = 'editor_field'; 
 if (this.options.submitOnBlur)
 textArea.onblur = this.onSubmit.bind(this);
 this.editField = textArea;
 }
 
 if(this.options.loadTextURL) {
 this.loadExternalText();
 }
 this.form.appendChild(this.editField);
 },
 getText: function() {
 return this.element.innerHTML;
 },
 loadExternalText: function() {
 Element.addClassName(this.form, this.options.loadingClassName);
 this.editField.disabled = true;
 new Ajax.Request(
 this.options.loadTextURL,
 Object.extend({
 asynchronous: true,
 onComplete: this.onLoadedExternalText.bind(this)
 }, this.options.ajaxOptions)
 );
 },
 onLoadedExternalText: function(transport) {
 Element.removeClassName(this.form, this.options.loadingClassName);
 this.editField.disabled = false;
 this.editField.value = transport.responseText.stripTags();
 Field.scrollFreeActivate(this.editField);
 },
 onclickCancel: function() {
 this.onComplete();
 this.leaveEditMode();
 return false;
 },
 onFailure: function(transport) {
 this.options.onFailure(transport);
 if (this.oldInnerHTML) {
 this.element.innerHTML = this.oldInnerHTML;
 this.oldInnerHTML = null;
 }
 return false;
 },
 onSubmit: function() {
 // onLoading resets these so we need to save them away for the Ajax call
 var form = this.form;
 var value = this.editField.value;
 
 // do this first, sometimes the ajax call returns before we get a chance to switch on Saving...
 // which means this will actually switch on Saving... *after* we've left edit mode causing Saving...
 // to be displayed indefinitely
 this.onLoading();
 
 if (this.options.evalScripts) {
 new Ajax.Request(
 this.url, Object.extend({
 parameters: this.options.callback(form, value),
 onComplete: this.onComplete.bind(this),
 onFailure: this.onFailure.bind(this),
 asynchronous:true, 
 evalScripts:true
 }, this.options.ajaxOptions));
 } else {
 new Ajax.Updater(
 { success: this.element,
 // don't update on failure (this could be an option)
 failure: null }, 
 this.url, Object.extend({
 parameters: this.options.callback(form, value),
 onComplete: this.onComplete.bind(this),
 onFailure: this.onFailure.bind(this)
 }, this.options.ajaxOptions));
 }
 // stop the event to avoid a page refresh in Safari
 if (arguments.length > 1) {
 Event.stop(arguments[0]);
 }
 return false;
 },
 onLoading: function() {
 this.saving = true;
 this.removeForm();
 this.leaveHover();
 this.showSaving();
 },
 showSaving: function() {
 this.oldInnerHTML = this.element.innerHTML;
 this.element.innerHTML = this.options.savingText;
 Element.addClassName(this.element, this.options.savingClassName);
 this.element.style.backgroundColor = this.originalBackground;
 Element.show(this.element);
 },
 removeForm: function() {
 if(this.form) {
 if (this.form.parentNode) Element.remove(this.form);
 this.form = null;
 }
 },
 enterHover: function() {
 if (this.saving) return;
 this.element.style.backgroundColor = this.options.highlightcolor;
 if (this.effect) {
 this.effect.cancel();
 }
 Element.addClassName(this.element, this.options.hoverClassName)
 },
 leaveHover: function() {
 if (this.options.backgroundColor) {
 this.element.style.backgroundColor = this.oldBackground;
 }
 Element.removeClassName(this.element, this.options.hoverClassName)
 if (this.saving) return;
 this.effect = new Effect.Highlight(this.element, {
 startcolor: this.options.highlightcolor,
 endcolor: this.options.highlightendcolor,
 restorecolor: this.originalBackground
 });
 },
 leaveEditMode: function() {
 Element.removeClassName(this.element, this.options.savingClassName);
 this.removeForm();
 this.leaveHover();
 this.element.style.backgroundColor = this.originalBackground;
 Element.show(this.element);
 if (this.options.externalControl) {
 Element.show(this.options.externalControl);
 }
 this.editing = false;
 this.saving = false;
 this.oldInnerHTML = null;
 this.onLeaveEditMode();
 },
 onComplete: function(transport) {
 this.leaveEditMode();
 this.options.onComplete.bind(this)(transport, this.element);
 },
 onEnterEditMode: function() {},
 onLeaveEditMode: function() {},
 dispose: function() {
 if (this.oldInnerHTML) {
 this.element.innerHTML = this.oldInnerHTML;
 }
 this.leaveEditMode();
 Event.stopObserving(this.element, 'click', this.onclickListener);
 Event.stopObserving(this.element, 'mouseover', this.mouseoverListener);
 Event.stopObserving(this.element, 'mouseout', this.mouseoutListener);
 if (this.options.externalControl) {
 Event.stopObserving(this.options.externalControl, 'click', this.onclickListener);
 Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener);
 Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener);
 }
 }
};

Ajax.InPlaceCollectionEditor = Class.create();
Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype);
Object.extend(Ajax.InPlaceCollectionEditor.prototype, {
 createEditField: function() {
 if (!this.cached_selectTag) {
 var selectTag = document.createElement("select");
 var collection = this.options.collection || [];
 var optionTag;
 collection.each(function(e,i) {
 optionTag = document.createElement("option");
 optionTag.value = (e instanceof Array) ? e[0] : e;
 if((typeof this.options.value == 'undefined') && 
 ((e instanceof Array) ? this.element.innerHTML == e[1] : e == optionTag.value)) optionTag.selected = true;
 if(this.options.value==optionTag.value) optionTag.selected = true;
 optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e));
 selectTag.appendChild(optionTag);
 }.bind(this));
 this.cached_selectTag = selectTag;
 }

 this.editField = this.cached_selectTag;
 if(this.options.loadTextURL) this.loadExternalText();
 this.form.appendChild(this.editField);
 this.options.callback = function(form, value) {
 return "value=" + encodeURIComponent(value);
 }
 }
});

// Delayed observer, like Form.Element.Observer, 
// but waits for delay after last key input
// Ideal for live-search fields

Form.Element.DelayedObserver = Class.create();
Form.Element.DelayedObserver.prototype = {
 initialize: function(element, delay, callback) {
 this.delay = delay || 0.5;
 this.element = $(element);
 this.callback = callback;
 this.timer = null;
 this.lastValue = $F(this.element); 
 Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
 },
 delayedListener: function(event) {
 if(this.lastValue == $F(this.element)) return;
 if(this.timer) clearTimeout(this.timer);
 this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
 this.lastValue = $F(this.element);
 },
 onTimerEvent: function() {
 this.timer = null;
 this.callback(this.element, $F(this.element));
 }
};

// script.aculo.us slider.js v1.7.1_beta3, Fri May 25 17:19:41 +0200 2007

// Copyright (c) 2005-2007 Marty Haught, Thomas Fuchs
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/

if(!Control) var Control = {};
Control.Slider = Class.create();

// options:
// axis: 'vertical', or 'horizontal' (default)
//
// callbacks:
// onChange(value)
// onSlide(value)
Control.Slider.prototype = {
 initialize: function(handle, track, options) {
 var slider = this;

 if(handle instanceof Array) {
 this.handles = handle.collect( function(e) { return $(e) });
 } else {
 this.handles = [$(handle)];
 }

 this.track = $(track);
 this.options = options || {};

 this.axis = this.options.axis || 'horizontal';
 this.increment = this.options.increment || 1;
 this.step = parseInt(this.options.step || '1');
 this.range = this.options.range || $R(0,1);

 this.value = 0; // assure backwards compat
 this.values = this.handles.map( function() { return 0 });
 this.spans = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false;
 this.options.startSpan = $(this.options.startSpan || null);
 this.options.endSpan = $(this.options.endSpan || null);

 this.restricted = this.options.restricted || false;

 this.maximum = this.options.maximum || this.range.end;
 this.minimum = this.options.minimum || this.range.start;

 // Will be used to align the handle onto the track, if necessary
 this.alignX = parseInt(this.options.alignX || '0');
 this.alignY = parseInt(this.options.alignY || '0');

 this.trackLength = this.maximumOffset() - this.minimumOffset();

 this.handleLength = this.isVertical() ?
 (this.handles[0].offsetHeight != 0 ?
 this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/,"")) :
 (this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth :
 this.handles[0].style.width.replace(/px$/,""));

 this.active = false;
 this.dragging = false;
 this.disabled = false;

 if(this.options.disabled) this.setDisabled();

 // Allowed values array
 this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false;
 if(this.allowedValues) {
 this.minimum = this.allowedValues.min();
 this.maximum = this.allowedValues.max();
 }

 this.eventMouseDown = this.startDrag.bindAsEventListener(this);
 this.eventMouseUp = this.endDrag.bindAsEventListener(this);
 this.eventMouseMove = this.update.bindAsEventListener(this);

 // Initialize handles in reverse (make sure first handle is active)
 this.handles.each( function(h,i) {
 i = slider.handles.length-1-i;
 slider.setValue(parseFloat(
 (slider.options.sliderValue instanceof Array ?
 slider.options.sliderValue[i] : slider.options.sliderValue) ||
 slider.range.start), i);
 Element.makePositioned(h); // fix IE
 Event.observe(h, "mousedown", slider.eventMouseDown);
 });

 Event.observe(this.track, "mousedown", this.eventMouseDown);
 Event.observe(document, "mouseup", this.eventMouseUp);
 Event.observe(this.track.parentNode.parentNode, "mousemove", this.eventMouseMove);

 this.initialized = true;
 },
 dispose: function() {
 var slider = this;
 Event.stopObserving(this.track, "mousedown", this.eventMouseDown);
 Event.stopObserving(document, "mouseup", this.eventMouseUp);
 Event.stopObserving(this.track.parentNode.parentNode, "mousemove", this.eventMouseMove);
 this.handles.each( function(h) {
 Event.stopObserving(h, "mousedown", slider.eventMouseDown);
 });
 },
 setDisabled: function(){
 this.disabled = true;
 },
 setEnabled: function(){
 this.disabled = false;
 },
 getNearestValue: function(value){
 if(this.allowedValues){
 if(value >= this.allowedValues.max()) return(this.allowedValues.max());
 if(value <= this.allowedValues.min()) return(this.allowedValues.min());

 var offset = Math.abs(this.allowedValues[0] - value);
 var newValue = this.allowedValues[0];
 this.allowedValues.each( function(v) {
 var currentOffset = Math.abs(v - value);
 if(currentOffset <= offset){
 newValue = v;
 offset = currentOffset;
 }
 });
 return newValue;
 }
 if(value > this.range.end) return this.range.end;
 if(value < this.range.start) return this.range.start;
 return value;
 },
 setValue: function(sliderValue, handleIdx){
 if(!this.active) {
 this.activeHandleIdx = handleIdx || 0;
 this.activeHandle = this.handles[this.activeHandleIdx];
 this.updateStyles();
 }
 handleIdx = handleIdx || this.activeHandleIdx || 0;
 if(this.initialized && this.restricted) {
 if((handleIdx>0) && (sliderValue<this.values[handleIdx-1]))
 sliderValue = this.values[handleIdx-1];
 if((handleIdx < (this.handles.length-1)) && (sliderValue>this.values[handleIdx+1]))
 sliderValue = this.values[handleIdx+1];
 }
 sliderValue = this.getNearestValue(sliderValue);
 this.values[handleIdx] = sliderValue;
 this.value = this.values[0]; // assure backwards compat

 this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] =
 this.translateToPx(sliderValue);

 this.drawSpans();
 if(!this.dragging || !this.event) this.updateFinished();
 },
 setValueBy: function(delta, handleIdx) {
 this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta,
 handleIdx || this.activeHandleIdx || 0);
 },
 translateToPx: function(value) {
 return Math.round(
 ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) *
 (value - this.range.start)) + "px";
 },
 translateToValue: function(offset) {
 return ((offset/(this.trackLength-this.handleLength) *
 (this.range.end-this.range.start)) + this.range.start);
 },
 getRange: function(range) {
 var v = this.values.sortBy(Prototype.K);
 range = range || 0;
 return $R(v[range],v[range+1]);
 },
 minimumOffset: function(){
 return(this.isVertical() ? this.alignY : this.alignX);
 },
 maximumOffset: function(){
 return(this.isVertical() ?
 (this.track.offsetHeight != 0 ? this.track.offsetHeight :
 this.track.style.height.replace(/px$/,"")) - this.alignY :
 (this.track.offsetWidth != 0 ? this.track.offsetWidth :
 this.track.style.width.replace(/px$/,"")) - this.alignY);
 },
 isVertical: function(){
 return (this.axis == 'vertical');
 },
 drawSpans: function() {
 var slider = this;
 if(this.spans)
 $R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) });
 if(this.options.startSpan)
 this.setSpan(this.options.startSpan,
 $R(0, this.values.length>1 ? this.getRange(0).min() : this.value ));
 if(this.options.endSpan)
 this.setSpan(this.options.endSpan,
 $R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum));
 },
 setSpan: function(span, range) {
 if(this.isVertical()) {
 span.style.top = this.translateToPx(range.start);
 span.style.height = this.translateToPx(range.end - range.start + this.range.start);
 } else {
 span.style.left = this.translateToPx(range.start);
 span.style.width = this.translateToPx(range.end - range.start + this.range.start);
 }
 },
 updateStyles: function() {
 this.handles.each( function(h){ Element.removeClassName(h, 'selected') });
 Element.addClassName(this.activeHandle, 'selected');
 },
 startDrag: function(event) {
 if(Event.isLeftClick(event)) {
 if(!this.disabled){
 this.active = true;

 var handle = Event.element(event);
 var pointer = [Event.pointerX(event), Event.pointerY(event)];
 var track = handle;
 if(track==this.track) {
 var offsets = Position.cumulativeOffset(this.track);
 this.event = event;
 this.setValue(this.translateToValue(
 (this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2)
 ));
 var offsets = Position.cumulativeOffset(this.activeHandle);
 this.offsetX = (pointer[0] - offsets[0]);
 this.offsetY = (pointer[1] - offsets[1]);
 } else {
 // find the handle (prevents issues with Safari)
 while((this.handles.indexOf(handle) == -1) && handle.parentNode)
 handle = handle.parentNode;

 if(this.handles.indexOf(handle)!=-1) {
 this.activeHandle = handle;
 this.activeHandleIdx = this.handles.indexOf(this.activeHandle);
 this.updateStyles();

 var offsets = Position.cumulativeOffset(this.activeHandle);
 this.offsetX = (pointer[0] - offsets[0]);
 this.offsetY = (pointer[1] - offsets[1]);
 }
 }
 }
 Event.stop(event);
 }
 },
 update: function(event) {
 if(this.active) {
 if(!this.dragging) this.dragging = true;
 this.draw(event);
 if(Prototype.Browser.WebKit) window.scrollBy(0,0);
 Event.stop(event);
 }
 },
 draw: function(event) {
 var pointer = [Event.pointerX(event), Event.pointerY(event)];
 var offsets = Position.cumulativeOffset(this.track);
 pointer[0] -= this.offsetX + offsets[0];
 pointer[1] -= this.offsetY + offsets[1];
 this.event = event;
 this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] ));
 if(this.initialized && this.options.onSlide)
 this.options.onSlide(this.values.length>1 ? this.values : this.value, this);
 },
 endDrag: function(event) {
 if(this.active && this.dragging) {
 this.finishDrag(event, true);
 Event.stop(event);
 }
 this.active = false;
 this.dragging = false;
 },
 finishDrag: function(event, success) {
 this.active = false;
 this.dragging = false;
 this.updateFinished();
 },
 updateFinished: function() {
 if(this.initialized && this.options.onChange)
 this.options.onChange(this.values.length>1 ? this.values : this.value, this);
 this.event = null;
 }
}
/**
 * Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Academic Free License (AFL 3.0)
 * that is bundled with this package in the file LICENSE_AFL.txt.
 * It is also available through the world-wide-web at this URL:
 * http://opensource.org/licenses/afl-3.0.php
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@magentocommerce.com so we can send you a copy immediately.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Magento to newer
 * versions in the future. If you wish to customize Magento for your
 * needs please refer to http://www.magentocommerce.com for more information.
 *
 * @copyright Copyright (c) 2008 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
 * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
 */
function popWin(url,win,para) {
 var win = window.open(url,win,para);
 win.focus();
}

function setLocation(url){
 window.location.href = url;
}

function setPLocation(url, setFocus){
 if( setFocus ) {
 window.opener.focus();
 }
 window.opener.location.href = url;
}

function setLanguageCode(code, fromCode){
 //TODO: javascript cookies have different domain and path than php cookies
 var href = window.location.href;
 var after = '', dash;
 if (dash = href.match(/\#(.*)$/)) {
 href = href.replace(/\#(.*)$/, '');
 after = dash[0];
 }

 if (href.match(/[?]/)) {
 var re = /([?&]store=)[a-z0-9_]*/;
 if (href.match(re)) {
 href = href.replace(re, '$1'+code);
 } else {
 href += '&store='+code;
 }

 var re = /([?&]from_store=)[a-z0-9_]*/;
 if (href.match(re)) {
 href = href.replace(re, '');
 }
 } else {
 href += '?store='+code;
 }
 if (typeof(fromCode) != 'undefined') {
 href += '&from_store='+fromCode;
 }
 href += after;

 setLocation(href);
}

/**
 * Add classes to specified elements.
 * Supported classes are: 'odd', 'even', 'first', 'last'
 *
 * @param elements - array of elements to be decorated
 * [@param decorateParams] - array of classes to be set. If omitted, all available will be used
 */
function decorateGeneric(elements, decorateParams)
{
 var allSupportedParams = ['odd', 'even', 'first', 'last'];
 var _decorateParams = {};
 var total = elements.length;

 if (total) {
 // determine params called
 if (typeof(decorateParams) == 'undefined') {
 decorateParams = allSupportedParams;
 }
 if (!decorateParams.length) {
 return;
 }
 for (var k in allSupportedParams) {
 _decorateParams[allSupportedParams[k]] = false;
 }
 for (var k in decorateParams) {
 _decorateParams[decorateParams[k]] = true;
 }

 // decorate elements
 // elements[0].addClassName('first'); // will cause bug in IE (#5587)
 if (_decorateParams.first) {
 Element.addClassName(elements[0], 'first');
 }
 if (_decorateParams.last) {
 Element.addClassName(elements[total-1], 'last');
 }
 for (var i = 0; i < total; i++) {
 if ((i + 1) % 2 == 0) {
 if (_decorateParams.even) {
 Element.addClassName(elements[i], 'even');
 }
 }
 else {
 if (_decorateParams.odd) {
 Element.addClassName(elements[i], 'odd');
 }
 }
 }
 }
}

/**
 * Decorate table rows and cells, tbody etc
 * @see decorateGeneric()
 */
function decorateTable(table, options) {
 var table = $(table);
 if (table) {
 // set default options
 var _options = {
 'tbody' : false,
 'tbody tr' : ['odd', 'even', 'first', 'last'],
 'thead tr' : ['first', 'last'],
 'tfoot tr' : ['first', 'last'],
 'tr td' : ['last']
 };
 // overload options
 if (typeof(options) != 'undefined') {
 for (var k in options) {
 _options[k] = options[k];
 }
 }
 // decorate
 if (_options['tbody']) {
 decorateGeneric(table.select('tbody'), _options['tbody']);
 }
 if (_options['tbody tr']) {
 decorateGeneric(table.select('tbody tr'), _options['tbody tr']);
 }
 if (_options['thead tr']) {
 decorateGeneric(table.select('thead tr'), _options['thead tr']);
 }
 if (_options['tfoot tr']) {
 decorateGeneric(table.select('tfoot tr'), _options['tfoot tr']);
 }
 if (_options['tr td']) {
 var allRows = table.select('tr');
 if (allRows.length) {
 for (var i = 0; i < allRows.length; i++) {
 decorateGeneric(allRows[i].getElementsByTagName('TD'), _options['tr td']);
 }
 }
 }
 }
}

/**
 * Set "odd", "even" and "last" CSS classes for list items
 * @see decorateGeneric()
 */
function decorateList(list, nonRecursive) {
 if ($(list)) {
 if (typeof(nonRecursive) == 'undefined') {
 var items = $(list).select('li')
 }
 else {
 var items = $(list).childElements();
 }
 decorateGeneric(items, ['odd', 'even', 'last']);
 }
}

/**
 * Set "odd", "even" and "last" CSS classes for list items
 * @see decorateGeneric()
 */
function decorateDataList(list) {
 list = $(list);
 if (list) {
 decorateGeneric(list.select('dt'), ['odd', 'even', 'last']);
 decorateGeneric(list.select('dd'), ['odd', 'even', 'last']);
 }
}

/**
 * Formats currency using patern
 * format - JSON (pattern, decimal, decimalsDelimeter, groupsDelimeter)
 * showPlus - true (always show '+'or '-'),
 * false (never show '-' even if number is negative)
 * null (show '-' if number is negative)
 */

function formatCurrency(price, format, showPlus){
 precision = isNaN(format.precision = Math.abs(format.precision)) ? 2 : format.precision;
 requiredPrecision = isNaN(format.requiredPrecision = Math.abs(format.requiredPrecision)) ? 2 : format.requiredPrecision;

 //precision = (precision > requiredPrecision) ? precision : requiredPrecision;
 //for now we don't need this difference so precision is requiredPrecision
 precision = requiredPrecision;

 integerRequired = isNaN(format.integerRequired = Math.abs(format.integerRequired)) ? 1 : format.integerRequired;

 decimalSymbol = format.decimalSymbol == undefined ? "," : format.decimalSymbol;
 groupSymbol = format.groupSymbol == undefined ? "." : format.groupSymbol;
 groupLength = format.groupLength == undefined ? 3 : format.groupLength;

 if (showPlus == undefined || showPlus == true) {
 s = price < 0 ? "-" : ( showPlus ? "+" : "");
 } else if (showPlus == false) {
 s = '';
 }

 i = parseInt(price = Math.abs(+price || 0).toFixed(precision)) + "";
 pad = (i.length < integerRequired) ? (integerRequired - i.length) : 0;
 while (pad) { i = '0' + i; pad--; }

 j = (j = i.length) > groupLength ? j % groupLength : 0;
 re = new RegExp("(\\d{" + groupLength + "})(?=\\d)", "g");

 /**
 * replace(/-/, 0) is only for fixing Safari bug which appears
 * when Math.abs(0).toFixed() executed on "0" number.
 * Result is "0.-0" :(
 */
 r = (j ? i.substr(0, j) + groupSymbol : "") + i.substr(j).replace(re, "$1" + groupSymbol) + (precision ? decimalSymbol + Math.abs(price - i).toFixed(precision).replace(/-/, 0).slice(2) : "")

 if (format.pattern.indexOf('{sign}') == -1) {
 pattern = s + format.pattern;
 } else {
 pattern = format.pattern.replace('{sign}', s);
 }

 return pattern.replace('%s', r).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
};

function expandDetails(el, childClass) {
 if (Element.hasClassName(el,'show-details')) {
 $$(childClass).each(function(item){item.hide()});
 Element.removeClassName(el,'show-details');
 }
 else {
 $$(childClass).each(function(item){item.show()});
 Element.addClassName(el,'show-details');
 }
}

// Version 1.0
var isIE = navigator.appVersion.match(/MSIE/) == "MSIE";

if (!window.Varien)
 var Varien = new Object();

Varien.showLoading = function(){
 Element.show('loading-process');
}
Varien.hideLoading = function(){
 Element.hide('loading-process');
}
Varien.GlobalHandlers = {
 onCreate: function() {
 Varien.showLoading();
 },

 onComplete: function() {
 if(Ajax.activeRequestCount == 0) {
 Varien.hideLoading();
 }
 }
};

Ajax.Responders.register(Varien.GlobalHandlers);

/**
 * Quick Search form client model
 */
Varien.searchForm = Class.create();
Varien.searchForm.prototype = {
 initialize : function(form, field, emptyText){
 this.form = $(form);
 this.field = $(field);
 this.emptyText = emptyText;

 Event.observe(this.form, 'submit', this.submit.bind(this));
 Event.observe(this.field, 'focus', this.focus.bind(this));
 Event.observe(this.field, 'blur', this.blur.bind(this));
 this.blur();
 },

 submit : function(event){
 if (this.field.value == this.emptyText || this.field.value == ''){
 Event.stop(event);
 return false;
 }
 return true;
 },

 focus : function(event){
 if(this.field.value==this.emptyText){
 this.field.value='';
 }

 },

 blur : function(event){
 if(this.field.value==''){
 this.field.value=this.emptyText;
 }
 },

 initAutocomplete : function(url, destinationElement){
 new Ajax.Autocompleter(
 this.field,
 destinationElement,
 url,
 {
 paramName: this.field.name,
 minChars: 2,
 updateElement: this._selectAutocompleteItem.bind(this),
 onShow : function(element, update) { 
 if(!update.style.position || update.style.position=='absolute') {
 update.style.position = 'absolute';
 Position.clone(element, update, {
 setHeight: false, 
 offsetTop: element.offsetHeight
 });
 }
 Effect.Appear(update,{duration:0});
 }

 }
 );
 },

 _selectAutocompleteItem : function(element){
 if(element.title){
 this.field.value = element.title;
 }
 this.form.submit();
 }
}

Varien.Tabs = Class.create();
Varien.Tabs.prototype = {
 initialize: function(selector) {
 var self=this;
 $$(selector+' a').each(this.initTab.bind(this));
 },

 initTab: function(el) {
 el.href = 'javascript:void(0)';
 if ($(el.parentNode).hasClassName('active')) {
 this.showContent(el);
 }
 el.observe('click', this.showContent.bind(this, el));
 },

 showContent: function(a) {
 var li = $(a.parentNode), ul = $(li.parentNode);
 ul.getElementsBySelector('li', 'ol').each(function(el){
 var contents = $(el.id+'_contents');
 if (el==li) {
 el.addClassName('active');
 contents.show();
 } else {
 el.removeClassName('active');
 contents.hide();
 }
 });
 }
}

Varien.DOB = Class.create();
Varien.DOB.prototype = {
 initialize: function(selector, required, format) {
 var el = $$(selector)[0];
 this.day = Element.select($(el), '.dob-day input')[0];
 this.month = Element.select($(el), '.dob-month input')[0];
 this.year = Element.select($(el), '.dob-year input')[0];
 this.dob = Element.select($(el), '.dob-full input')[0];
 this.advice = Element.select($(el), '.validation-advice')[0];
 this.required = required;
 this.format = format;

 this.day.validate = this.validate.bind(this);
 this.month.validate = this.validate.bind(this);
 this.year.validate = this.validate.bind(this);

 this.advice.hide();
 },

 validate: function() {
 var error = false;

 if (this.day.value=='' && this.month.value=='' && this.year.value=='') {
 if (this.required) {
 error = 'This date is a required value.';
 } else {
 this.dob.value = '';
 }
 } else if (this.day.value=='' || this.month.value=='' || this.year.value=='') {
 error = 'Please enter a valid full date.';
 } else {
 var date = new Date();
 if (this.day.value<1 || this.day.value>31) {
 error = 'Please enter a valid day (1-31).';
 } else if (this.month.value<1 || this.month.value>12) {
 error = 'Please enter a valid month (1-12).';
 } else if (this.year.value<1900 || this.year.value>date.getFullYear()) {
 error = 'Please enter a valid year (1900-'+date.getFullYear()+').';
 } else {
 this.dob.value = this.format.replace(/(%m|%b)/i, this.month.value).replace(/(%d|%e)/i, this.day.value).replace(/%y/i, this.year.value);
 var testDOB = this.month.value + '/' + this.day.value + '/'+ this.year.value;
 var test = new Date(testDOB);
 if (isNaN(test)) {
 error = 'Please enter a valid date.';
 }
 }
 }

 if (error !== false) {
 try {
 this.advice.innerHTML = Translator.translate(error);
 }
 catch (e) {
 this.advice.innerHTML = error;
 }
 this.advice.show();
 return false;
 }

 this.advice.hide();
 return true;
 }
}

Validation.addAllThese([
 ['validate-custom', ' ', function(v,elm) {
 return elm.validate();
 }]
]);

function truncateOptions() {
 $$('.truncated').each(function(element){
 Event.observe(element, 'mouseover', function(){
 if (element.down('div.truncated_full_value')) {
 element.down('div.truncated_full_value').addClassName('show')
 }
 });
 Event.observe(element, 'mouseout', function(){
 if (element.down('div.truncated_full_value')) {
 element.down('div.truncated_full_value').removeClassName('show')
 }
 });

 });
}
Event.observe(window, 'load', function(){
 truncateOptions();
});
/**
 * Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Academic Free License (AFL 3.0)
 * that is bundled with this package in the file LICENSE_AFL.txt.
 * It is also available through the world-wide-web at this URL:
 * http://opensource.org/licenses/afl-3.0.php
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@magentocommerce.com so we can send you a copy immediately.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Magento to newer
 * versions in the future. If you wish to customize Magento for your
 * needs please refer to http://www.magentocommerce.com for more information.
 *
 * @copyright Copyright (c) 2008 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
 * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
 */
VarienForm = Class.create();
VarienForm.prototype = {
 initialize: function(formId, firstFieldFocus){
 this.form = $(formId);
 if (!this.form) {
 return;
 }
 this.cache = $A();
 this.currLoader = false;
 this.currDataIndex = false;
 this.validator = new Validation(this.form);
 this.elementFocus = this.elementOnFocus.bindAsEventListener(this);
 this.elementBlur = this.elementOnBlur.bindAsEventListener(this);
 this.childLoader = this.onChangeChildLoad.bindAsEventListener(this);
 this.highlightClass = 'highlight';
 this.extraChildParams = '';
 this.firstFieldFocus= firstFieldFocus || false;
 this.bindElements();
 if(this.firstFieldFocus){
 try{
 Form.Element.focus(Form.findFirstElement(this.form))
 }
 catch(e){}
 }
 },

 submit : function(url){
 if(this.validator && this.validator.validate()){
 this.form.submit();
 }
 return false;
 },

 bindElements:function (){
 var elements = Form.getElements(this.form);
 for (var row in elements) {
 if (elements[row].id) {
 Event.observe(elements[row],'focus',this.elementFocus);
 Event.observe(elements[row],'blur',this.elementBlur);
 }
 }
 },

 elementOnFocus: function(event){
 var element = Event.findElement(event, 'fieldset');
 if(element){
 Element.addClassName(element, this.highlightClass);
 }
 },

 elementOnBlur: function(event){
 var element = Event.findElement(event, 'fieldset');
 if(element){
 Element.removeClassName(element, this.highlightClass);
 }
 },

 setElementsRelation: function(parent, child, dataUrl, first){
 if (parent=$(parent)) {
 // TODO: array of relation and caching
 if (!this.cache[parent.id]){
 this.cache[parent.id] = $A();
 this.cache[parent.id]['child'] = child;
 this.cache[parent.id]['dataUrl'] = dataUrl;
 this.cache[parent.id]['data'] = $A();
 this.cache[parent.id]['first'] = first || false;
 }
 Event.observe(parent,'change',this.childLoader);
 }
 },

 onChangeChildLoad: function(event){
 element = Event.element(event);
 this.elementChildLoad(element);
 },

 elementChildLoad: function(element, callback){
 this.callback = callback || false;
 if (element.value) {
 this.currLoader = element.id;
 this.currDataIndex = element.value;
 if (this.cache[element.id]['data'][element.value]) {
 this.setDataToChild(this.cache[element.id]['data'][element.value]);
 }
 else{
 new Ajax.Request(this.cache[this.currLoader]['dataUrl'],{
 method: 'post',
 parameters: {"parent":element.value},
 onComplete: this.reloadChildren.bind(this)
 });
 }
 }
 },

 reloadChildren: function(transport){
 var data = eval('(' + transport.responseText + ')');
 this.cache[this.currLoader]['data'][this.currDataIndex] = data;
 this.setDataToChild(data);
 },

 setDataToChild: function(data){
 if (data.length) {
 var child = $(this.cache[this.currLoader]['child']);
 if (child){
 var html = '<select name="'+child.name+'" id="'+child.id+'" class="'+child.className+'" title="'+child.title+'" '+this.extraChildParams+'>';
 if(this.cache[this.currLoader]['first']){
 html+= '<option value="">'+this.cache[this.currLoader]['first']+'</option>';
 }
 for (var i in data){
 if(data[i].value) {
 html+= '<option value="'+data[i].value+'"';
 if(child.value && (child.value == data[i].value || child.value == data[i].label)){
 html+= ' selected';
 }
 html+='>'+data[i].label+'</option>';
 }
 }
 html+= '</select>';
 Element.insert(child, {before: html});
 Element.remove(child);
 }
 }
 else{
 var child = $(this.cache[this.currLoader]['child']);
 if (child){
 var html = '<input type="text" name="'+child.name+'" id="'+child.id+'" class="'+child.className+'" title="'+child.title+'" '+this.extraChildParams+'>';
 Element.insert(child, {before: html});
 Element.remove(child);
 }
 }

 this.bindElements();
 if (this.callback) {
 this.callback();
 }
 }
}

RegionUpdater = Class.create();
RegionUpdater.prototype = {
 initialize: function (countryEl, regionTextEl, regionSelectEl, regions, disableAction)
 {
 this.countryEl = $(countryEl);
 this.regionTextEl = $(regionTextEl);
 this.regionSelectEl = $(regionSelectEl);
 this.regions = regions;

 this.disableAction = (typeof disableAction=='undefined') ? 'hide' : disableAction;

 if (this.regionSelectEl.options.length<=1) {
 this.update();
 }

 Event.observe(this.countryEl, 'change', this.update.bind(this));
 },

 update: function()
 {
 if (this.regions[this.countryEl.value]) {
 var i, option, region, def;

 if (this.regionTextEl) {
 def = this.regionTextEl.value.toLowerCase();
 this.regionTextEl.value = '';
 }
 if (!def) {
 def = this.regionSelectEl.getAttribute('defaultValue');
 }

 this.regionSelectEl.options.length = 1;
 for (regionId in this.regions[this.countryEl.value]) {
 region = this.regions[this.countryEl.value][regionId];

 option = document.createElement('OPTION');
 option.value = regionId;
 option.text = region.name;

 if (this.regionSelectEl.options.add) {
 this.regionSelectEl.options.add(option);
 } else {
 this.regionSelectEl.appendChild(option);
 }

 if (regionId==def || region.name.toLowerCase()==def || region.code.toLowerCase()==def) {
 this.regionSelectEl.value = regionId;
 }
 }

 if (this.disableAction=='hide') {
 if (this.regionTextEl) {
 this.regionTextEl.style.display = 'none';
 }

 this.regionSelectEl.style.display = '';
 } else if (this.disableAction=='disable') {
 if (this.regionTextEl) {
 this.regionTextEl.disabled = true;
 }
 this.regionSelectEl.disabled = false;
 }
 this.setMarkDisplay(this.regionSelectEl, true);
 } else {
 if (this.disableAction=='hide') {
 if (this.regionTextEl) {
 this.regionTextEl.style.display = '';
 }
 this.regionSelectEl.style.display = 'none';
 Validation.reset(this.regionSelectEl);
 } else if (this.disableAction=='disable') {
 if (this.regionTextEl) {
 this.regionTextEl.disabled = false;
 }
 this.regionSelectEl.disabled = true;
 } else if (this.disableAction=='nullify') {
 this.regionSelectEl.options.length = 1;
 this.regionSelectEl.value = '';
 this.regionSelectEl.selectedIndex = 0;
 this.lastCountryId = '';
 }
 this.setMarkDisplay(this.regionSelectEl, false);
 }
 },

 setMarkDisplay: function(elem, display){
 elem = $(elem);
 var labelElement = elem.up(1).down('label > span.required') || 
 elem.up(2).down('label > span.required') ||
 elem.up(1).down('label.required > em') ||
 elem.up(2).down('label.required > em');
 if(labelElement) {
 display ? labelElement.show() : labelElement.hide();
 }
 }
}
/**
 * Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Academic Free License (AFL 3.0)
 * that is bundled with this package in the file LICENSE_AFL.txt.
 * It is also available through the world-wide-web at this URL:
 * http://opensource.org/licenses/afl-3.0.php
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@magentocommerce.com so we can send you a copy immediately.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Magento to newer
 * versions in the future. If you wish to customize Magento for your
 * needs please refer to http://www.magentocommerce.com for more information.
 *
 * @copyright Copyright (c) 2008 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
 * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
 */
function toggleMenu(el, over)
{
 if (over) {
 Element.addClassName(el, 'over');
 }
 else {
 Element.removeClassName(el, 'over');
 }
}

/**
 * Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Academic Free License (AFL 3.0)
 * that is bundled with this package in the file LICENSE_AFL.txt.
 * It is also available through the world-wide-web at this URL:
 * http://opensource.org/licenses/afl-3.0.php
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@magentocommerce.com so we can send you a copy immediately.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Magento to newer
 * versions in the future. If you wish to customize Magento for your
 * needs please refer to http://www.magentocommerce.com for more information.
 *
 * @category Mage
 * @package Js
 * @copyright Copyright (c) 2008 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
 * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
 */

var Translate = Class.create();
Translate.prototype = {
 initialize: function(data){
 this.data = $H(data);
 },

 translate : function(){
 var args = arguments;
 var text = arguments[0];

 if(this.data.get(text)){
 return this.data.get(text);
 }
 return text;
 },
 add : function() {
 if (arguments.length > 1) {
 this.data.set(arguments[0], arguments[1]);
 } else if (typeof arguments[0] =='object') {
 $H(arguments[0]).each(function (pair){
 this.data.set(pair.key, pair.value);
 }.bind(this));
 }
 }
}
/**
 * Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Academic Free License (AFL 3.0)
 * that is bundled with this package in the file LICENSE_AFL.txt.
 * It is also available through the world-wide-web at this URL:
 * http://opensource.org/licenses/afl-3.0.php
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@magentocommerce.com so we can send you a copy immediately.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Magento to newer
 * versions in the future. If you wish to customize Magento for your
 * needs please refer to http://www.magentocommerce.com for more information.
 *
 * @copyright Copyright (c) 2008 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
 * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
 */
// old school cookie functions grabbed off the web

if (!window.Mage) var Mage = {};

Mage.Cookies = {};
Mage.Cookies.set = function(name, value){
 var argv = arguments;
 var argc = arguments.length;
 var expires = (argc > 2) ? argv[2] : null;
 var path = (argc > 3) ? argv[3] : '/';
 var domain = (argc > 4) ? argv[4] : null;
 var secure = (argc > 5) ? argv[5] : false;
 document.cookie = name + "=" + escape (value) +
 ((expires == null) ? "" : ("; expires=" + expires.toGMTString())) +
 ((path == null) ? "" : ("; path=" + path)) +
 ((domain == null) ? "" : ("; domain=" + domain)) +
 ((secure == true) ? "; secure" : "");
};

Mage.Cookies.get = function(name){
 var arg = name + "=";
 var alen = arg.length;
 var clen = document.cookie.length;
 var i = 0;
 var j = 0;
 while(i < clen){
 j = i + alen;
 if (document.cookie.substring(i, j) == arg)
 return Mage.Cookies.getCookieVal(j);
 i = document.cookie.indexOf(" ", i) + 1;
 if(i == 0)
 break;
 }
 return null;
};

Mage.Cookies.clear = function(name) {
 if(Mage.Cookies.get(name)){
 document.cookie = name + "=" +
 "; expires=Thu, 01-Jan-70 00:00:01 GMT";
 }
};

Mage.Cookies.getCookieVal = function(offset){
 var endstr = document.cookie.indexOf(";", offset);
 if(endstr == -1){
 endstr = document.cookie.length;
 }
 return unescape(document.cookie.substring(offset, endstr));
};
