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 Y={6Q:\'1.6.0.2\',1w:{2N:!!(1i.5J&&!1i.6R),3J:!!1i.6R,3j:3K.3L.2O(\'bp/\')>-1,5K:3K.3L.2O(\'5K\')>-1&&3K.3L.2O(\'8A\')==-1,8B:!!3K.3L.1k(/bq.*br.*8C/)},2P:{5L:!!V.2b,4R:!!1i.4S,5M:V.2Q(\'2k\').3M&&V.2Q(\'2k\').3M!==V.2Q(\'6S\').3M},5N:\'<4T[^>]*>([\\\\S\\\\s]*?)<\\/4T>\',8D:/^\\/\\*-bs-([\\s\\S]*)\\*\\/\\s*$/,2q:q(){},K:q(x){o x}};E(Y.1w.8B)Y.2P.5M=1d;G 1E={1L:q(){G a=17,4U=$A(1c);E(J.1M(4U[0]))a=4U.3N();q 2r(){C.22.2B(C,1c)}J.U(2r,1E.W);2r.6T=a;2r.8E=[];E(a){G b=q(){};b.18=a.18;2r.18=1e b;a.8E.14(2r)}N(G i=0;i<4U.M;i++)2r.4V(4U[i]);E(!2r.18.22)2r.18.22=Y.2q;2r.18.bt=2r;o 2r}};1E.W={4V:q(a){G b=C.6T&&C.6T.18;G c=J.4g(a);E(!J.4g({24:1f}).M)c.14("24","8F");N(G i=0,M=c.M;i<M;i++){G d=c[i],1g=a[d];E(b&&J.1M(1g)&&1g.8G().2C()=="$2Y"){G e=1g,1g=J.U((q(m){o q(){o b[m].2B(C,1c)}})(d).3O(e),{8F:q(){o e},24:q(){o e.24()}})}C.18[d]=1g}o C}};G 3P={};J.U=q(a,b){N(G c 1s b)a[c]=b[c];o a};J.U(J,{1W:q(a){1N{E(J.1X(a))o\'3k\';E(a===17)o\'17\';o a.1W?a.1W():1B(a)}1Y(e){E(e 8H bu)o\'...\';3l e;}},2s:q(a){G b=2R a;4h(b){1O\'3k\':1O\'q\':1O\'bv\':o;1O\'bw\':o a.24()}E(a===17)o\'17\';E(a.2s)o a.2s();E(J.2Z(a))o;G c=[];N(G d 1s a){G e=J.2s(a[d]);E(!J.1X(e))c.14(d.2s()+\': \'+e)}o\'{\'+c.1P(\', \')+\'}\'},3m:q(a){o $H(a).3m()},31:q(a){o a&&a.31?a.31():1B.4i(a)},4g:q(a){G b=[];N(G c 1s a)b.14(c);o b},25:q(a){G b=[];N(G c 1s a)b.14(a[c]);o b},1Z:q(a){o J.U({},a)},2Z:q(a){o a&&a.2t==1},3n:q(a){o a!=17&&2R a=="2D"&&\'bx\'1s a&&\'1P\'1s a},6U:q(a){o a 8H 2S},1M:q(a){o 2R a=="q"},2l:q(a){o 2R a=="5O"},3Q:q(a){o 2R a=="by"},1X:q(a){o 2R a=="3k"}});J.U(6V.18,{8G:q(){G a=C.24().1k(/^[\\s\\(]*q[^(]*\\((.*?)\\)/)[1].32(",").5P("2T");o a.M==1&&!a[0]?[]:a},1o:q(){E(1c.M<2&&J.1X(1c[0]))o C;G a=C,2c=$A(1c),2D=2c.3N();o q(){o a.2B(2D,2c.1z($A(1c)))}},bz:q(){G b=C,2c=$A(1c),2D=2c.3N();o q(a){o b.2B(2D,[a||1i.bA].1z(2c))}},5Q:q(){E(!1c.M)o C;G a=C,2c=$A(1c);o q(){o a.2B(C,2c.1z($A(1c)))}},6W:q(){G a=C,2c=$A(1c),8I=2c.3N()*8J;o 1i.bB(q(){o a.2B(a,2c)},8I)},3O:q(a){G b=C;o q(){o a.2B(C,[b.1o(C)].1z($A(1c)))}},3o:q(){E(C.6X)o C.6X;G a=C;o C.6X=q(){o a.2B(17,[C].1z($A(1c)))}}});6V.18.3p=6V.18.6W.5Q(0.bC);bD.18.2s=q(){o\'"\'+C.bE()+\'-\'+(C.bF()+1).3q(2)+\'-\'+C.bG().3q(2)+\'T\'+C.bH().3q(2)+\':\'+C.bI().3q(2)+\':\'+C.bJ().3q(2)+\'Z"\'};G 8K={8L:q(){G a;N(G i=0,M=1c.M;i<M;i++){G b=1c[i];1N{a=b();1F}1Y(e){}}o a}};3a.18.1k=3a.18.2d;3a.8M=q(a){o 1B(a).1x(/([.*+?^=!:${}()|[\\]\\/\\\\])/g,\'\\\\$1\')};G 8N=1E.1L({22:q(a,b){C.4W=a;C.4X=b;C.5R=1d;C.4Y()},4Y:q(){C.4j=8O(C.4Z.1o(C),C.4X*8J)},6Y:q(){C.4W(C)},6Z:q(){E(!C.4j)o;8P(C.4j);C.4j=17},4Z:q(){E(!C.5R){1N{C.5R=1f;C.6Y()}bK{C.5R=1d}}}});J.U(1B,{4i:q(a){o a==17?\'\':1B(a)},8Q:{\'\\b\':\'\\\\b\',\'\\t\':\'\\\\t\',\'\\n\':\'\\\\n\',\'\\f\':\'\\\\f\',\'\\r\':\'\\\\r\',\'\\\\\':\'\\\\\\\\\'}});J.U(1B.18,{2m:q(a,b){G c=\'\',3r=C,1k;b=1c.4k.70(b);1q(3r.M>0){E(1k=3r.1k(a)){c+=3r.3s(0,1k.50);c+=1B.4i(b(1k));3r=3r.3s(1k.50+1k[0].M)}19{c+=3r,3r=\'\'}}o c},8R:q(b,c,d){c=C.2m.70(c);d=J.1X(d)?1:d;o C.2m(b,q(a){E(--d<0)o a[0];o c(a)})},8S:q(a,b){C.2m(a,b);o 1B(C)},bL:q(a,b){a=a||30;b=J.1X(b)?\'...\':b;o C.M>a?C.3s(0,a-b.M)+b:1B(C)},2T:q(){o C.1x(/^\\s+/,\'\').1x(/\\s+$/,\'\')},8T:q(){o C.1x(/<\\/?[^>]+>/8U,\'\')},3b:q(){o C.1x(1e 3a(Y.5N,\'8V\'),\'\')},8W:q(){G b=1e 3a(Y.5N,\'8V\');G c=1e 3a(Y.5N,\'bM\');o(C.1k(b)||[]).2e(q(a){o(a.1k(c)||[\'\',\'\'])[1]})},3R:q(){o C.8W().2e(q(a){o 5S(a)})},5T:q(){G a=1c.4k;a.2U.bN=C;o a.2k.3t},8X:q(){G c=1e I(\'2k\');c.3t=C.8T();o c.2o[0]?(c.2o.M>1?$A(c.2o).2E(\'\',q(a,b){o a+b.71}):c.2o[0].71):\'\'},5U:q(e){G f=C.2T().1k(/([^?#]*)(#.*)?$/);E(!f)o{};o f[1].32(e||\'&\').2E({},q(a,b){E((b=b.32(\'=\'))[0]){G c=72(b.3N());G d=b.M>1?b.1P(\'=\'):b[0];E(d!=3k)d=72(d);E(c 1s a){E(!J.3n(a[c]))a[c]=[a[c]];a[c].14(d)}19 a[c]=d}o a})},2u:q(){o C.32(\'\')},73:q(){o C.3s(0,C.M-1)+1B.bO(C.8Y(C.M-1)+1)},5V:q(a){o a<1?\'\':1e 1I(a+1).1P(C)},74:q(){G a=C.32(\'-\'),75=a.M;E(75==1)o a[0];G b=C.5W(0)==\'-\'?a[0].5W(0).2f()+a[0].4l(1):a[0];N(G i=1;i<75;i++)b+=a[i].5W(0).2f()+a[i].4l(1);o b},51:q(){o C.5W(0).2f()+C.4l(1).1G()},bP:q(){o C.2m(/::/,\'/\').2m(/([A-Z]+)([A-Z][a-z])/,\'#{1}52#{2}\').2m(/([a-z\\d])([A-Z])/,\'#{1}52#{2}\').2m(/-/,\'52\').1G()},bQ:q(){o C.2m(/52/,\'-\')},1W:q(c){G d=C.2m(/[\\bR-\\bS\\\\]/,q(a){G b=1B.8Q[a[0]];o b?b:\'\\\\bT\'+a[0].8Y().3q(2,16)});E(c)o\'"\'+d.1x(/"/g,\'\\\\"\')+\'"\';o"\'"+d.1x(/\'/g,\'\\\\\\\'\')+"\'"},2s:q(){o C.1W(1f)},76:q(a){o C.8R(a||Y.8D,\'#{1}\')},8Z:q(){G a=C;E(a.3S())o 1d;a=C.1x(/\\\\./g,\'@\').1x(/"[^"\\\\\\n\\r]*"/g,\'\');o(/^[,:{}\\[\\]0-9.\\-+bU-u \\n\\r\\t]*$/).2d(a)},4m:q(a){G b=C.76();1N{E(!a||b.8Z())o 5S(\'(\'+b+\')\')}1Y(e){}3l 1e bV(\'bW bX 90 5O: \'+C.1W());},1p:q(a){o C.2O(a)>-1},77:q(a){o C.2O(a)===0},91:q(a){G d=C.M-a.M;o d>=0&&C.78(a)===d},4n:q(){o C==\'\'},3S:q(){o/^\\s*$/.2d(C)},92:q(a,b){o 1e 2g(C,b).2b(a)}});E(Y.1w.3j||Y.1w.2N)J.U(1B.18,{5T:q(){o C.1x(/&/g,\'&93;\').1x(/</g,\'&94;\').1x(/>/g,\'&95;\')},8X:q(){o C.1x(/&93;/g,\'&\').1x(/&94;/g,\'<\').1x(/&95;/g,\'>\')}});1B.18.2m.70=q(b){E(J.1M(b))o b;G c=1e 2g(b);o q(a){o c.2b(a)}};1B.18.bY=1B.18.5U;J.U(1B.18.5T,{2k:V.2Q(\'2k\'),2U:V.96(\'\')});97(1B.18.5T)2k.4o(2U);G 2g=1E.1L({22:q(a,b){C.98=a.24();C.99=b||2g.9a},2b:q(f){E(J.1M(f.79))f=f.79();o C.98.2m(C.99,q(a){E(f==17)o\'\';G b=a[1]||\'\';E(b==\'\\\\\')o a[2];G c=f,53=a[3];G d=/^([^.[]+|\\[((?:.*?[^\\\\])?)\\])(\\.|\\[|$)/;a=d.9b(53);E(a==17)o b;1q(a!=17){G e=a[1].77(\'[\')?a[2].2m(\'\\\\\\\\]\',\']\'):a[1];c=c[e];E(17==c||\'\'==a[3])1F;53=53.4l(\'[\'==a[3]?a[1].M:a[0].M);a=d.9b(53)}o b+1B.4i(c)})}});2g.9a=/(^|.|\\r|\\n)(#\\{(.*?)\\})/;G $1F={};G 26={1l:q(b,c){G d=0;b=b.1o(c);1N{C.3c(q(a){b(a,d++)})}1Y(e){E(e!=$1F)3l e;}o C},9c:q(a,b,c){b=b?b.1o(c):Y.K;G d=-a,7a=[],7b=C.2u();1q((d+=a)<7b.M)7a.14(7b.3s(d,d+a));o 7a.7c(b,c)},7d:q(c,d){c=c?c.1o(d):Y.K;G e=1f;C.1l(q(a,b){e=e&&!!c(a,b);E(!e)3l $1F;});o e},9d:q(c,d){c=c?c.1o(d):Y.K;G e=1d;C.1l(q(a,b){E(e=!!c(a,b))3l $1F;});o e},7c:q(c,d){c=c?c.1o(d):Y.K;G e=[];C.1l(q(a,b){e.14(c(a,b))});o e},5X:q(c,d){c=c.1o(d);G e;C.1l(q(a,b){E(c(a,b)){e=a;3l $1F;}});o e},4p:q(c,d){c=c.1o(d);G e=[];C.1l(q(a,b){E(c(a,b))e.14(a)});o e},bZ:q(c,d,e){d=d?d.1o(e):Y.K;G f=[];E(J.2l(c))c=1e 3a(c);C.1l(q(a,b){E(c.1k(a))f.14(d(a,b))});o f},1p:q(b){E(J.1M(C.2O))E(C.2O(b)!=-1)o 1f;G c=1d;C.1l(q(a){E(a==b){c=1f;3l $1F;}});o c},c0:q(b,c){c=J.1X(c)?17:c;o C.9c(b,q(a){1q(a.M<b)a.14(c);o a})},2E:q(c,d,e){d=d.1o(e);C.1l(q(a,b){c=d(c,a,b)});o c},5P:q(b){G c=$A(1c).3s(1);o C.2e(q(a){o a[b].2B(a,c)})},c1:q(c,d){c=c?c.1o(d):Y.K;G e;C.1l(q(a,b){a=c(a,b);E(e==17||a>=e)e=a});o e},c2:q(c,d){c=c?c.1o(d):Y.K;G e;C.1l(q(a,b){a=c(a,b);E(e==17||a<e)e=a});o e},c3:q(c,d){c=c?c.1o(d):Y.K;G e=[],7e=[];C.1l(q(a,b){(c(a,b)?e:7e).14(a)});o[e,7e]},4q:q(b){G c=[];C.1l(q(a){c.14(a[b])});o c},c4:q(c,d){c=c.1o(d);G e=[];C.1l(q(a,b){E(!c(a,b))e.14(a)});o e},9e:q(e,f){e=e.1o(f);o C.2e(q(a,b){o{1g:a,54:e(a,b)}}).c5(q(c,d){G a=c.54,b=d.54;o a<b?-1:a>b?1:0}).4q(\'1g\')},2u:q(){o C.2e()},c6:q(){G c=Y.K,2c=$A(1c);E(J.1M(2c.1Q()))c=2c.c7();G d=[C].1z(2c).2e($A);o C.2e(q(a,b){o c(d.4q(b))})},9f:q(){o C.2u().M},1W:q(){o\'#<26:\'+C.2u().1W()+\'>\'}};J.U(26,{2e:26.7c,7f:26.5X,20:26.4p,4r:26.4p,c8:26.1p,c9:26.2u,ca:26.7d,cb:26.9d});q $A(a){E(!a)o[];E(a.2u)o a.2u();G b=a.M||0,15=1e 1I(b);1q(b--)15[b]=a[b];o 15}E(Y.1w.3j){$A=q(a){E(!a)o[];E(!(J.1M(a)&&a==\'[2D cc]\')&&a.2u)o a.2u();G b=a.M||0,15=1e 1I(b);1q(b--)15[b]=a[b];o 15}}1I.9g=$A;J.U(1I.18,26);E(!1I.18.7g)1I.18.7g=1I.18.55;J.U(1I.18,{3c:q(a){N(G i=0,M=C.M;i<M;i++)a(C[i])},9h:q(){C.M=0;o C},2C:q(){o C[0]},1Q:q(){o C[C.M-1]},cd:q(){o C.20(q(a){o a!=17})},9i:q(){o C.2E([],q(a,b){o a.1z(J.3n(b)?b.9i():[b])})},56:q(){G b=$A(1c);o C.20(q(a){o!b.1p(a)})},55:q(a){o(a!==1d?C:C.2u()).7g()},ce:q(){o C.M>1?C:C[0]},9j:q(d){o C.2E([],q(a,b,c){E(0==c||(d?a.1Q()!=b:!a.1p(b)))a.14(b);o a})},cf:q(c){o C.9j().4p(q(b){o c.5X(q(a){o b===a})})},1Z:q(){o[].1z(C)},9f:q(){o C.M},1W:q(){o\'[\'+C.2e(J.1W).1P(\', \')+\']\'},2s:q(){G c=[];C.1l(q(a){G b=J.2s(a);E(!J.1X(b))c.14(b)});o\'[\'+c.1P(\', \')+\']\'}});E(J.1M(1I.18.9k))1I.18.3c=1I.18.9k;E(!1I.18.2O)1I.18.2O=q(a,i){i||(i=0);G b=C.M;E(i<0)i=b+i;N(;i<b;i++)E(C[i]===a)o i;o-1};E(!1I.18.78)1I.18.78=q(a,i){i=cg(i)?C.M:(i<0?C.M+i:i)+1;G n=C.3s(0,i).55().2O(a);o(n<0)?n:i-n-1};1I.18.2u=1I.18.1Z;q $w(a){E(!J.2l(a))o[];a=a.2T();o a?a.32(/\\s+/):[]}E(Y.1w.3J){1I.18.1z=q(){G a=[];N(G i=0,M=C.M;i<M;i++)a.14(C[i]);N(G i=0,M=1c.M;i<M;i++){E(J.3n(1c[i])){N(G j=0,9l=1c[i].M;j<9l;j++)a.14(1c[i][j])}19{a.14(1c[i])}}o a}}J.U(3T.18,{ch:q(){o C.3q(2,16)},73:q(){o C+1},5V:q(a){$R(0,C,1f).1l(a);o C},3q:q(a,b){G c=C.24(b||10);o\'0\'.5V(a-c.M)+c},2s:q(){o ci(C)?C.24():\'17\'}});$w(\'cj ck cl cm\').1l(q(a){3T.18[a]=co[a].3o()});q $H(a){o 1e 2S(a)};G 2S=1E.1L(26,(q(){q 7h(a,b){E(J.1X(b))o a;o a+\'=\'+9m(1B.4i(b))}o{22:q(a){C.3u=J.6U(a)?a.57():J.1Z(a)},3c:q(a){N(G b 1s C.3u){G c=C.3u[b],5Y=[b,c];5Y.4s=b;5Y.1g=c;a(5Y)}},58:q(a,b){o C.3u[a]=b},7i:q(a){o C.3u[a]},cp:q(a){G b=C.3u[a];7j C.3u[a];o b},57:q(){o J.1Z(C.3u)},4g:q(){o C.4q(\'4s\')},25:q(){o C.4q(\'1g\')},50:q(b){G c=C.5X(q(a){o a.1g===b});o c&&c.4s},cq:q(a){o C.1Z().3U(a)},3U:q(c){o 1e 2S(c).2E(C,q(a,b){a.58(b.4s,b.1g);o a})},3m:q(){o C.2e(q(a){G b=9m(a.4s),25=a.1g;E(25&&2R 25==\'2D\'){E(J.3n(25))o 25.2e(7h.5Q(b)).1P(\'&\')}o 7h(b,25)}).1P(\'&\')},1W:q(){o\'#<2S:{\'+C.2e(q(a){o a.2e(J.1W).1P(\': \')}).1P(\', \')+\'}>\'},2s:q(){o J.2s(C.57())},1Z:q(){o 1e 2S(C)}}})());2S.18.79=2S.18.57;2S.9g=$H;G 9n=1E.1L(26,{22:q(a,b,c){C.59=a;C.7k=b;C.9o=c},3c:q(a){G b=C.59;1q(C.1p(b)){a(b);b=b.73()}},1p:q(a){E(a<C.59)o 1d;E(C.9o)o a<C.7k;o a<=C.7k}});G $R=q(a,b,c){o 1e 9n(a,b,c)};G 1t={9p:q(){o 8K.8L(q(){o 1e 9q()},q(){o 1e 9r(\'cr.9s\')},q(){o 1e 9r(\'cs.9s\')})||1d},7l:0};1t.4t={5a:[],3c:q(a){C.5a.3c(a)},9t:q(a){E(!C.1p(a))C.5a.14(a)},ct:q(a){C.5a=C.5a.56(a)},5Z:q(b,c,d,f){C.1l(q(a){E(J.1M(a[b])){1N{a[b].2B(a,[c,d,f])}1Y(e){}}})}};J.U(1t.4t,26);1t.4t.9t({60:q(){1t.7l++},3v:q(){1t.7l--}});1t.7m=1E.1L({22:q(a){C.1b={28:\'5b\',61:1f,9u:\'62/x-cu-6S-cv\',7n:\'cw-8\',2v:\'\',4m:1f,7o:1f};J.U(C.1b,a||{});C.1b.28=C.1b.28.1G();E(J.2l(C.1b.2v))C.1b.2v=C.1b.2v.5U();19 E(J.6U(C.1b.2v))C.1b.2v=C.1b.2v.57()}});1t.3V=1E.1L(1t.7m,{7p:1d,22:q($2Y,b,c){$2Y(c);C.1R=1t.9p();C.2V(b)},2V:q(a){C.3W=a;C.28=C.1b.28;G b=J.1Z(C.1b.2v);E(![\'7i\',\'5b\'].1p(C.28)){b[\'cx\']=C.28;C.28=\'5b\'}C.2v=b;E(b=J.3m(b)){E(C.28==\'7i\')C.3W+=(C.3W.1p(\'?\')?\'&\':\'?\')+b;19 E(/cy|8C|8A/.2d(3K.3L))b+=\'&52=\'}1N{G c=1e 1t.7q(C);E(C.1b.60)C.1b.60(c);1t.4t.5Z(\'60\',C,c);C.1R.cz(C.28.2f(),C.3W,C.1b.61);E(C.1b.61)C.7r.1o(C).3p(1);C.1R.63=C.7s.1o(C);C.9v();C.1S=C.28==\'5b\'?(C.1b.cA||b):17;C.1R.cB(C.1S);E(!C.1b.61&&C.1R.9w)C.7s()}1Y(e){C.3X(e)}},7s:q(){G a=C.1R.2W;E(a>1&&!((a==4)&&C.7p))C.7r(C.1R.2W)},9v:q(){G b={\'X-cC-cD\':\'9q\',\'X-Y-6Q\':Y.6Q,\'cE\':\'2U/cF, 2U/cG, 62/9x, 2U/9x, */*\'};E(C.28==\'5b\'){b[\'7t-1n\']=C.1b.9u+(C.1b.7n?\'; cH=\'+C.1b.7n:\'\');E(C.1R.9w&&(3K.3L.1k(/5K\\/(\\d{4})/)||[0,9y])[1]<9y)b[\'cI\']=\'cJ\'}E(2R C.1b.9z==\'2D\'){G c=C.1b.9z;E(J.1M(c.14))N(G i=0,M=c.M;i<M;i+=2)b[c[i]]=c[i+1];19 $H(c).1l(q(a){b[a.4s]=a.1g})}N(G d 1s b)C.1R.cK(d,b[d])},3Y:q(){G a=C.5c();o!a||(a>=cL&&a<cM)},5c:q(){1N{o C.1R.64||0}1Y(e){o 0}},7r:q(a){G b=1t.3V.9A[a],3d=1e 1t.7q(C);E(b==\'7u\'){1N{C.7p=1f;(C.1b[\'4u\'+3d.64]||C.1b[\'4u\'+(C.3Y()?\'cN\':\'cO\')]||Y.2q)(3d,3d.65)}1Y(e){C.3X(e)}G c=3d.4v(\'7t-1n\');E(C.1b.7o==\'9B\'||(C.1b.7o&&C.66()&&c&&c.1k(/^\\s*(2U|62)\\/(x-)?(cP|cQ)4T(;.*)?\\s*$/i)))C.9C()}1N{(C.1b[\'4u\'+b]||Y.2q)(3d,3d.65);1t.4t.5Z(\'4u\'+b,C,3d,3d.65)}1Y(e){C.3X(e)}E(b==\'7u\'){C.1R.63=Y.2q}},66:q(){G m=C.3W.1k(/^\\s*cR?:\\/\\/[^\\/]*/);o!m||(m[0]==\'#{7v}//#{7w}#{67}\'.92({7v:68.7v,7w:V.7w,67:68.67?\':\'+68.67:\'\'}))},4v:q(a){1N{o C.1R.7x(a)||17}1Y(e){o 17}},9C:q(){1N{o 5S((C.1R.3w||\'\').76())}1Y(e){C.3X(e)}},3X:q(a){(C.1b.9D||Y.2q)(C,a);1t.4t.5Z(\'9D\',C,a)}});1t.3V.9A=[\'cS\',\'cT\',\'cU\',\'cV\',\'7u\'];1t.7q=1E.1L({22:q(a){C.2V=a;G b=C.1R=a.1R,2W=C.2W=b.2W;E((2W>2&&!Y.1w.2N)||2W==4){C.64=C.5c();C.7y=C.9E();C.3w=1B.4i(b.3w);C.65=C.9F()}E(2W==4){G c=b.9G;C.9G=J.1X(c)?17:c;C.cW=C.9H()}},64:0,7y:\'\',5c:1t.3V.18.5c,9E:q(){1N{o C.1R.7y||\'\'}1Y(e){o\'\'}},4v:1t.3V.18.4v,cX:q(){1N{o C.7z()}1Y(e){o 17}},7x:q(a){o C.1R.7x(a)},7z:q(){o C.1R.7z()},9F:q(){G a=C.4v(\'X-90\');E(!a)o 17;a=72(8M(a));1N{o a.4m(C.2V.1b.9I||!C.2V.66())}1Y(e){C.2V.3X(e)}},9H:q(){G a=C.2V.1b;E(!a.4m||(a.4m!=\'9B\'&&!(C.4v(\'7t-1n\')||\'\').1p(\'62/cY\'))||C.3w.3S())o 17;1N{o C.3w.4m(a.9I||!C.2V.66())}1Y(e){C.2V.3X(e)}}});1t.9J=1E.1L(1t.3V,{22:q($2Y,d,e,f){C.69={3Y:(d.3Y||d),7A:(d.7A||(d.3Y?17:d))};f=J.1Z(f);G g=f.3v;f.3v=(q(a,b){C.9K(a.3w);E(J.1M(g))g(a,b)}).1o(C);$2Y(e,f)},9K:q(a){G b=C.69[C.3Y()?\'3Y\':\'7A\'],1b=C.1b;E(!1b.3R)a=a.3b();E(b=$(b)){E(1b.6a){E(J.2l(1b.6a)){G c={};c[1b.6a]=a;b.2w(c)}19 1b.6a(b,a)}19 b.3U(a)}}});1t.cZ=1E.1L(1t.7m,{22:q($2Y,b,c,d){$2Y(d);C.3v=C.1b.3v;C.4X=(C.1b.4X||2);C.3Z=(C.1b.3Z||1);C.7B={};C.69=b;C.3W=c;C.59()},59:q(){C.1b.3v=C.9L.1o(C);C.4Z()},6Z:q(){C.7B.1b.3v=3k;d0(C.4j);(C.3v||Y.2q).2B(C,1c)},9L:q(a){E(C.1b.3Z){C.3Z=(a.3w==C.9M?C.3Z*C.1b.3Z:1);C.9M=a.3w}C.4j=C.4Z.1o(C).6W(C.3Z*C.4X)},4Z:q(){C.7B=1e 1t.9J(C.69,C.3W,C.1b)}});q $(a){E(1c.M>1){N(G i=0,7C=[],M=1c.M;i<M;i++)7C.14($(1c[i]));o 7C}E(J.2l(a))a=V.d1(a);o I.U(a)}E(Y.2P.5L){V.7D=q(a,b){G c=[];G d=V.2b(a,$(b)||V,17,d2.d3,17);N(G i=0,M=d.d4;i<M;i++)c.14(I.U(d.d5(i)));o c}}E(!1i.5d)G 5d={};E(!5d.9N){J.U(5d,{9N:1,d6:2,9O:3,d7:4,d8:5,d9:6,da:7,db:8,dc:9,dd:10,de:11,df:12})}(q(){G d=C.I;C.I=q(a,b){b=b||{};a=a.1G();G c=I.5e;E(Y.1w.2N&&b.21){a=\'<\'+a+\' 21="\'+b.21+\'">\';7j b.21;o I.5f(V.2Q(a),b)}E(!c[a])c[a]=I.U(V.2Q(a));o I.5f(c[a].dg(1d),b)};J.U(C.I,d||{})}).7E(1i);I.5e={};I.W={7F:q(a){o $(a).1a.3e!=\'6b\'},9P:q(a){a=$(a);I[I.7F(a)?\'9Q\':\'9R\'](a);o a},9Q:q(a){$(a).1a.3e=\'6b\';o a},9R:q(a){$(a).1a.3e=\'\';o a},9S:q(a){a=$(a);a.1A.5g(a);o a},3U:q(a,b){a=$(a);E(b&&b.2x)b=b.2x();E(J.2Z(b))o a.3U().2w(b);b=J.31(b);a.3t=b.3b();b.3R.1o(b).3p();o a},1x:q(a,b){a=$(a);E(b&&b.2x)b=b.2x();19 E(!J.2Z(b)){b=J.31(b);G c=a.dh.di();c.dj(a);b.3R.1o(b).3p();b=c.dk(b.3b())}a.1A.7G(b,a);o a},2w:q(a,b){a=$(a);E(J.2l(b)||J.3Q(b)||J.2Z(b)||(b&&(b.2x||b.31)))b={41:b};G c,2w,1h,2o;N(G d 1s b){c=b[d];d=d.1G();2w=I.4w[d];E(c&&c.2x)c=c.2x();E(J.2Z(c)){2w(a,c);2F}c=J.31(c);1h=((d==\'7H\'||d==\'6c\')?a.1A:a).1h.2f();2o=I.6d(1h,c.3b());E(d==\'2h\'||d==\'6c\')2o.55();2o.1l(2w.5Q(a));c.3R.1o(c).3p()}o a},3O:q(a,b,c){a=$(a);E(J.2Z(b))$(b).5f(c||{});19 E(J.2l(b))b=1e I(b,c);19 b=1e I(\'2k\',b);E(a.1A)a.1A.7G(b,a);b.4o(a);o b},1W:q(d){d=$(d);G e=\'<\'+d.1h.1G();$H({\'29\':\'29\',\'1J\':\'5h\'}).1l(q(a){G b=a.2C(),9T=a.1Q();G c=(d[b]||\'\').24();E(c)e+=\' \'+9T+\'=\'+c.1W(1f)});o e+\'>\'},6e:q(a,b){a=$(a);G c=[];1q(a=a[b])E(a.2t==1)c.14(I.U(a));o c},7I:q(a){o $(a).6e(\'1A\')},9U:q(a){o $(a).20("*")},9V:q(a){a=$(a).4x;1q(a&&a.2t!=1)a=a.3x;o $(a)},9W:q(a){E(!(a=$(a).4x))o[];1q(a&&a.2t!=1)a=a.3x;E(a)o[a].1z($(a).5i());o[]},7J:q(a){o $(a).6e(\'9X\')},5i:q(a){o $(a).6e(\'3x\')},dl:q(a){a=$(a);o a.7J().55().1z(a.5i())},1k:q(a,b){E(J.2l(b))b=1e O(b);o b.1k($(a))},dm:q(a,b,c){a=$(a);E(1c.M==1)o $(a.1A);G d=a.7I();o J.3Q(b)?d[b]:O.4y(d,b,c)},dn:q(a,b,c){a=$(a);E(1c.M==1)o a.9V();o J.3Q(b)?a.9U()[b]:a.20(b)[c||0]},dp:q(a,b,c){a=$(a);E(1c.M==1)o $(O.1C.5j(a));G d=a.7J();o J.3Q(b)?d[b]:O.4y(d,b,c)},9Y:q(a,b,c){a=$(a);E(1c.M==1)o $(O.1C.5k(a));G d=a.5i();o J.3Q(b)?d[b]:O.4y(d,b,c)},20:q(){G a=$A(1c),1u=$(a.3N());o O.6f(1u,a)},42:q(){G a=$A(1c),1u=$(a.3N());o O.6f(1u.1A,a).56(1u)},9Z:q(a){a=$(a);G b=a.43(\'29\'),7K=1c.4k;E(b)o b;do{b=\'dq\'+7K.a0++}1q($(b));a.5f(\'29\',b);o b},43:q(a,b){a=$(a);E(Y.1w.2N){G t=I.2G.6g;E(t.25[b])o t.25[b](a,b);E(t.3y[b])b=t.3y[b];E(b.1p(\':\')){o(!a.7L||!a.7L[b])?17:a.7L[b].1g}}o a.7M(b)},5f:q(a,b,c){a=$(a);G d={},t=I.2G.5l;E(2R b==\'2D\')d=b;19 d[b]=J.1X(c)?1f:c;N(G e 1s d){b=t.3y[e]||e;c=d[e];E(t.25[e])b=t.25[e](a,c);E(c===1d||c===17)a.7N(b);19 E(c===1f)a.a1(b,b);19 a.a1(b,c)}o a},a2:q(a){o $(a).4z().2y},a3:q(a){o $(a).4z().1T},5m:q(a){o 1e I.6h(a)},6i:q(a,b){E(!(a=$(a)))o;G c=a.1J;o(c.M>0&&(c==b||1e 3a("(^|\\\\s)"+b+"(\\\\s|$)").2d(c)))},a4:q(a,b){E(!(a=$(a)))o;E(!a.6i(b))a.1J+=(a.1J?\' \':\'\')+b;o a},a5:q(a,b){E(!(a=$(a)))o;a.1J=a.1J.1x(1e 3a("(^|\\\\s+)"+b+"(\\\\s+|$)"),\' \').2T();o a},dr:q(a,b){E(!(a=$(a)))o;o a[a.6i(b)?\'a5\':\'a4\'](b)},ds:q(a){a=$(a);G b=a.4x;1q(b){G c=b.3x;E(b.2t==3&&!/\\S/.2d(b.71))a.5g(b);b=c}o a},4n:q(a){o $(a).3t.3S()},6j:q(b,c){b=$(b),c=$(c);G d=c;E(b.a6)o(b.a6(c)&8)===8;E(b.5n&&!Y.1w.3J){G e=b.5n,a=c.5n,4A=c.3x;E(!4A){do{c=c.1A}1q(!(4A=c.3x)&&c.1A)}E(4A&&4A.5n)o(e>a&&e<4A.5n)}1q(b=b.1A)E(b==d)o 1f;o 1d},a7:q(a){a=$(a);G b=a.44();1i.a7(b[0],b[1]);o a},1D:q(a,b){a=$(a);b=b==\'7O\'?\'6k\':b.74();G c=a.1a[b];E(!c){G d=V.dt.du(a,17);c=d?d[b]:17}E(b==\'2H\')o c?4B(c):1.0;o c==\'6l\'?17:c},dv:q(a){o $(a).1D(\'2H\')},4C:q(a,b){a=$(a);G c=a.1a,1k;E(J.2l(b)){a.1a.7P+=\';\'+b;o b.1p(\'2H\')?a.4D(b.1k(/2H:\\s*(\\d?\\.?\\d*)/)[1]):a}N(G d 1s b)E(d==\'2H\')a.4D(b[d]);19 c[(d==\'7O\'||d==\'6k\')?(J.1X(c.7Q)?\'6k\':\'7Q\'):d]=b[d];o a},4D:q(a,b){a=$(a);a.1a.2H=(b==1||b===\'\')?\'\':(b<0.6m)?0:b;o a},4z:q(a){a=$(a);G b=$(a).1D(\'3e\');E(b!=\'6b\'&&b!=17)o{1T:a.4E,2y:a.4F};G c=a.1a;G d=c.7R;G e=c.1v;G f=c.3e;c.7R=\'6n\';c.1v=\'4G\';c.3e=\'dw\';G g=a.a8;G h=a.a9;c.3e=f;c.1v=e;c.7R=d;o{1T:g,2y:h}},dx:q(a){a=$(a);G b=I.1D(a,\'1v\');E(b==\'4H\'||!b){a.7S=1f;a.1a.1v=\'5o\';E(1i.6R){a.1a.2h=0;a.1a.2I=0}}o a},dy:q(a){a=$(a);E(a.7S){a.7S=3k;a.1a.1v=a.1a.2h=a.1a.2I=a.1a.41=a.1a.6o=\'\'}o a},dz:q(a){a=$(a);E(a.47)o a;a.47=I.1D(a,\'7T\')||\'6l\';E(a.47!==\'6n\')a.1a.7T=\'6n\';o a},dA:q(a){a=$(a);E(!a.47)o a;a.1a.7T=a.47==\'6l\'?\'\':a.47;a.47=17;o a},44:q(a){G b=0,2a=0;do{b+=a.48||0;2a+=a.49||0;a=a.3f}1q(a);o I.4a(2a,b)},5p:q(a){G b=0,2a=0;do{b+=a.48||0;2a+=a.49||0;a=a.3f;E(a){E(a.1h==\'aa\')1F;G p=I.1D(a,\'1v\');E(p!==\'4H\')1F}}1q(a);o I.4a(2a,b)},7U:q(a){a=$(a);E(a.1D(\'1v\')==\'4G\')o;G b=a.5p();G c=b[1];G d=b[0];G e=a.a8;G f=a.a9;a.ab=d-4B(a.1a.2I||0);a.ac=c-4B(a.1a.2h||0);a.ad=a.1a.1T;a.ae=a.1a.2y;a.1a.1v=\'4G\';a.1a.2h=c+\'2p\';a.1a.2I=d+\'2p\';a.1a.1T=e+\'2p\';a.1a.2y=f+\'2p\';o a},7V:q(a){a=$(a);E(a.1D(\'1v\')==\'5o\')o;a.1a.1v=\'5o\';G b=4B(a.1a.2h||0)-(a.ac||0);G c=4B(a.1a.2I||0)-(a.ab||0);a.1a.2h=b+\'2p\';a.1a.2I=c+\'2p\';a.1a.2y=a.ae;a.1a.1T=a.ad;o a},7W:q(a){G b=0,2a=0;do{b+=a.3z||0;2a+=a.3A||0;a=a.1A}1q(a);o I.4a(2a,b)},4I:q(a){E(a.3f)o $(a.3f);E(a==V.1S)o $(a);1q((a=a.1A)&&a!=V.1S)E(I.1D(a,\'1v\')!=\'4H\')o $(a);o $(V.1S)},5q:q(a){G b=0,2a=0;G c=a;do{b+=c.48||0;2a+=c.49||0;E(c.3f==V.1S&&I.1D(c,\'1v\')==\'4G\')1F}1q(c=c.3f);c=a;do{E(!Y.1w.3J||c.1h==\'aa\'){b-=c.3z||0;2a-=c.3A||0}}1q(c=c.1A);o I.4a(2a,b)},af:q(a,b){G c=J.U({ag:1f,ah:1f,ai:1f,aj:1f,48:0,49:0},1c[2]||{});b=$(b);G p=b.5q();a=$(a);G d=[0,0];G e=17;E(I.1D(a,\'1v\')==\'4G\'){e=a.4I();d=e.5q()}E(e==V.1S){d[0]-=V.1S.49;d[1]-=V.1S.48}E(c.ag)a.1a.2I=(p[0]-d[0]+c.49)+\'2p\';E(c.ah)a.1a.2h=(p[1]-d[1]+c.48)+\'2p\';E(c.ai)a.1a.1T=b.4E+\'2p\';E(c.aj)a.1a.2y=b.4F+\'2p\';o a}};I.W.9Z.a0=1;J.U(I.W,{dB:I.W.20,dC:I.W.9W});I.2G={5l:{3y:{1J:\'5h\',ak:\'N\'},25:{}}};E(Y.1w.3J){I.W.1D=I.W.1D.3O(q(d,e,f){4h(f){1O\'2I\':1O\'2h\':1O\'6o\':1O\'41\':E(d(e,\'1v\')===\'4H\')o 17;1O\'2y\':1O\'1T\':E(!I.7F(e))o 17;G g=al(d(e,f),10);E(g!==e[\'2i\'+f.51()])o g+\'2p\';G h;E(f===\'2y\'){h=[\'6p-2h-1T\',\'6q-2h\',\'6q-41\',\'6p-41-1T\']}19{h=[\'6p-2I-1T\',\'6q-2I\',\'6q-6o\',\'6p-6o-1T\']}o h.2E(g,q(a,b){G c=d(e,b);o c===17?a:a-al(c,10)})+\'2p\';5r:o d(e,f)}});I.W.43=I.W.43.3O(q(a,b,c){E(c===\'6r\')o b.6r;o a(b,c)})}19 E(Y.1w.2N){I.W.4I=I.W.4I.3O(q(a,b){b=$(b);G c=b.1D(\'1v\');E(c!==\'4H\')o a(b);b.4C({1v:\'5o\'});G d=a(b);b.4C({1v:c});o d});$w(\'5p 5q\').1l(q(f){I.W[f]=I.W[f].3O(q(a,b){b=$(b);G c=b.1D(\'1v\');E(c!==\'4H\')o a(b);G d=b.4I();E(d&&d.1D(\'1v\')===\'dD\')d.4C({7X:1});b.4C({1v:\'5o\'});G e=a(b);b.4C({1v:c});o e})});I.W.1D=q(a,b){a=$(a);b=(b==\'7O\'||b==\'6k\')?\'7Q\':b.74();G c=a.1a[b];E(!c&&a.7Y)c=a.7Y[b];E(b==\'2H\'){E(c=(a.1D(\'4r\')||\'\').1k(/7Z\\(2H=(.*)\\)/))E(c[1])o 4B(c[1])/am;o 1.0}E(c==\'6l\'){E((b==\'1T\'||b==\'2y\')&&(a.1D(\'3e\')!=\'6b\'))o a[\'2i\'+b.51()]+\'2p\';o 17}o c};I.W.4D=q(b,c){q 80(a){o a.1x(/7Z\\([^\\)]*\\)/8U,\'\')}b=$(b);G d=b.7Y;E((d&&!d.dE)||(!d&&b.1a.7X==\'dF\'))b.1a.7X=1;G e=b.1D(\'4r\'),1a=b.1a;E(c==1||c===\'\'){(e=80(e))?1a.4r=e:1a.7N(\'4r\');o b}19 E(c<0.6m)c=0;1a.4r=80(e)+\'7Z(2H=\'+(c*am)+\')\';o b};I.2G={6g:{3y:{\'5h\':\'1J\',\'N\':\'ak\'},25:{6s:q(a,b){o a.7M(b,2)},an:q(a,b){G c=a.ao(b);o c?c.1g:""},1K:q(a,b){b=a.7M(b);o b?b.24().3s(23,-2):17},5s:q(a,b){o $(a).2J(b)?b:17},1a:q(a){o a.1a.7P.1G()},6r:q(a){o a.6r}}}};I.2G.5l={3y:J.U({dG:\'dH\',dI:\'dJ\'},I.2G.6g.3y),25:{2K:q(a,b){a.2K=!!b},1a:q(a,b){a.1a.7P=b?b:\'\'}}};I.2G.81={};$w(\'dK dL dM dN dO 6t \'+\'dP dQ dR dS\').1l(q(a){I.2G.5l.3y[a.1G()]=a;I.2G.81[a.1G()]=a});(q(v){J.U(v,{ap:v.6s,aq:v.6s,1n:v.6s,4J:v.an,2z:v.5s,2K:v.5s,dT:v.5s,dU:v.5s,dV:v.1K,ar:v.1K,dW:v.1K,dX:v.1K,dY:v.1K,dZ:v.1K,e0:v.1K,e1:v.1K,e2:v.1K,e3:v.1K,e4:v.1K,e5:v.1K,e6:v.1K,e7:v.1K,e8:v.1K,e9:v.1K,ea:v.1K,eb:v.1K})})(I.2G.6g.25)}19 E(Y.1w.5K&&/ec:1\\.8\\.0/.2d(3K.3L)){I.W.4D=q(a,b){a=$(a);a.1a.2H=(b==1)?0.ed:(b===\'\')?\'\':(b<0.6m)?0:b;o a}}19 E(Y.1w.3j){I.W.4D=q(a,b){a=$(a);a.1a.2H=(b==1||b===\'\')?\'\':(b<0.6m)?0:b;E(b==1)E(a.1h==\'at\'&&a.1T){a.1T++;a.1T--}19 1N{G n=V.96(\' \');a.4o(n);a.5g(n)}1Y(e){}o a};I.W.44=q(a){G b=0,2a=0;do{b+=a.48||0;2a+=a.49||0;E(a.3f==V.1S)E(I.1D(a,\'1v\')==\'4G\')1F;a=a.3f}1q(a);o I.4a(2a,b)}}E(Y.1w.2N||Y.1w.3J){I.W.3U=q(b,c){b=$(b);E(c&&c.2x)c=c.2x();E(J.2Z(c))o b.3U().2w(c);c=J.31(c);G d=b.1h.2f();E(d 1s I.4w.3B){$A(b.2o).1l(q(a){b.5g(a)});I.6d(d,c.3b()).1l(q(a){b.4o(a)})}19 b.3t=c.3b();c.3R.1o(c).3p();o b}}E(\'au\'1s V.2Q(\'2k\')){I.W.1x=q(b,c){b=$(b);E(c&&c.2x)c=c.2x();E(J.2Z(c)){b.1A.7G(c,b);o b}c=J.31(c);G d=b.1A,1h=d.1h.2f();E(I.4w.3B[1h]){G e=b.9Y();G f=I.6d(1h,c.3b());d.5g(b);E(e)f.1l(q(a){d.6u(a,e)});19 f.1l(q(a){d.4o(a)})}19 b.au=c.3b();c.3R.1o(c).3p();o b}}I.4a=q(l,t){G a=[l,t];a.2I=l;a.2h=t;o a};I.6d=q(a,b){G c=1e I(\'2k\'),t=I.4w.3B[a];E(t){c.3t=t[0]+b+t[1];t[2].5V(q(){c=c.4x})}19 c.3t=b;o $A(c.2o)};I.4w={7H:q(a,b){a.1A.6u(b,a)},2h:q(a,b){a.6u(b,a.4x)},41:q(a,b){a.4o(b)},6c:q(a,b){a.1A.6u(b,a.3x)},3B:{ee:[\'<3C>\',\'</3C>\',1],6v:[\'<3C><4K>\',\'</4K></3C>\',2],av:[\'<3C><4K><6w>\',\'</6w></4K></3C>\',3],82:[\'<3C><4K><6w><aw>\',\'</aw></6w></4K></3C>\',4],ax:[\'<20>\',\'</20>\',1]}};(q(){J.U(C.3B,{ay:C.3B.6v,az:C.3B.6v,aA:C.3B.82})}).7E(I.4w);I.W.6x={2J:q(a,b){b=I.2G.81[b]||b;G c=$(a).ao(b);o c&&c.ef}};I.W.2A={};J.U(I,I.W);E(!Y.2P.4R&&V.2Q(\'2k\').3M){1i.4S={};1i.4S.18=V.2Q(\'2k\').3M;Y.2P.4R=1f}I.U=(q(){E(Y.2P.5M)o Y.K;G c={},2A=I.W.2A;G d=J.U(q(a){E(!a||a.6y||a.2t!=1||a==1i)o a;G b=J.1Z(c),1h=a.1h,5t,1g;E(2A[1h])J.U(b,2A[1h]);N(5t 1s b){1g=b[5t];E(J.1M(1g)&&!(5t 1s a))a[5t]=1g.3o()}a.6y=Y.2q;o a},{6z:q(){E(!Y.2P.4R){J.U(c,I.W);J.U(c,I.W.6x)}}});d.6z();o d})();I.2J=q(a,b){E(a.2J)o a.2J(b);o I.W.6x.2J(a,b)};I.4V=q(f){G F=Y.2P,T=I.W.2A;E(!f){J.U(1j,1j.W);J.U(1j.I,1j.I.W);J.U(I.W.2A,{"eg":J.1Z(1j.W),"eh":J.1Z(1j.I.W),"ax":J.1Z(1j.I.W),"aB":J.1Z(1j.I.W)})}E(1c.M==2){G g=f;f=1c[1]}E(!g)J.U(I.W,f||{});19{E(J.3n(g))g.1l(U);19 U(g)}q U(a){a=a.2f();E(!I.W.2A[a])I.W.2A[a]={};J.U(I.W.2A[a],f)}q 6A(a,b,c){c=c||1d;N(G d 1s a){G e=a[d];E(!J.1M(e))2F;E(!c||!(d 1s b))b[d]=e.3o()}}q aC(a){G b;G c={"ei":"ej","aB":"ek","P":"el","em":"eo","ep":"eq","er":"es","et":"eu","ev":"ew","ex":"4L","ey":"4L","ez":"4L","eA":"4L","eB":"4L","eC":"4L","Q":"eD","eE":"aD","eF":"aD","A":"eG","at":"eH","eI":"eJ","eK":"aE","eL":"aE","ay":"83","az":"83","6v":"83","av":"eM","aA":"aF","82":"aF","eN":"eO","eP":"eQ"};E(c[a])b=\'84\'+c[a]+\'I\';E(1i[b])o 1i[b];b=\'84\'+a+\'I\';E(1i[b])o 1i[b];b=\'84\'+a.51()+\'I\';E(1i[b])o 1i[b];1i[b]={};1i[b].18=V.2Q(a).3M;o 1i[b]}E(F.4R){6A(I.W,4S.18);6A(I.W.6x,4S.18,1f)}E(F.5M){N(G h 1s I.W.2A){G i=aC(h);E(J.1X(i))2F;6A(T[h],i.18)}}J.U(I,I.W);7j I.2A;E(I.U.6z)I.U.6z();I.5e={}};V.eR={4z:q(){G a={};G B=Y.1w;$w(\'1T 2y\').1l(q(d){G D=d.51();a[d]=(B.3j&&!V.2b)?7K[\'eS\'+D]:(B.3J)?V.1S[\'aG\'+D]:V.3D[\'aG\'+D]});o a},a3:q(){o C.4z().1T},a2:q(){o C.4z().2y},eT:q(){o I.4a(1i.aH||V.3D.3A||V.1S.3A,1i.aI||V.3D.3z||V.1S.3z)}};G O=1E.1L({22:q(a){C.2X=a.2T();C.aJ()},aK:q(){E(!Y.2P.5L)o 1d;G e=C.2X;E(Y.1w.3j&&(e.1p("-1U-1n")||e.1p(":4n")))o 1d;E((/(\\[[\\w-]*?:|:2K)/).2d(C.2X))o 1d;o 1f},aJ:q(){E(C.aK())o C.aL();G e=C.2X,3g=O.5u,h=O.1C,c=O.54,3h,p,m;E(O.4b[e]){C.2L=O.4b[e];o}C.2L=["C.2L = q(aM) {","G r = aM, h = O.1C, c = 1d, n;"];1q(e&&3h!=e&&(/\\S/).2d(e)){3h=e;N(G i 1s 3g){p=3g[i];E(m=e.1k(p)){C.2L.14(J.1M(c[i])?c[i](m):1e 2g(c[i]).2b(m));e=e.1x(m[0],\'\');1F}}}C.2L.14("o h.85(n);\\n}");5S(C.2L.1P(\'\\n\'));O.4b[C.2X]=C.2L},aL:q(){G e=C.2X,3g=O.5u,x=O.1V,3h,m;E(O.4b[e]){C.1V=O.4b[e];o}C.2L=[\'.//*\'];1q(e&&3h!=e&&(/\\S/).2d(e)){3h=e;N(G i 1s 3g){E(m=e.1k(3g[i])){C.2L.14(J.1M(x[i])?x[i](m):1e 2g(x[i]).2b(m));e=e.1x(m[0],\'\');1F}}}C.1V=C.2L.1P(\'\');O.4b[C.2X]=C.1V},6B:q(a){a=a||V;E(C.1V)o V.7D(C.1V,a);o C.2L(a)},1k:q(a){C.86=[];G e=C.2X,3g=O.5u,as=O.87;G b,p,m;1q(e&&b!==e&&(/\\S/).2d(e)){b=e;N(G i 1s 3g){p=3g[i];E(m=e.1k(p)){E(as[i]){C.86.14([i,J.1Z(m)]);e=e.1x(m[0],\'\')}19{o C.6B(V).1p(a)}}}}G c=1f,21,88;N(G i=0,6C;6C=C.86[i];i++){21=6C[0],88=6C[1];E(!O.87[21](a,88)){c=1d;1F}}o c},24:q(){o C.2X},1W:q(){o"#<O:"+C.2X.1W()+">"}});J.U(O,{4b:{},1V:{3E:"//*",1r:"/*",42:"/5v-3F::*[1]",5w:\'/5v-3F::*\',1h:q(m){E(m[1]==\'*\')o\'\';o"[aN-21()=\'"+m[1].1G()+"\' 89 aN-21()=\'"+m[1].2f()+"\']"},1J:"[5x(1z(\' \', @5h, \' \'), \' #{1} \')]",29:"[@29=\'#{1}\']",4M:q(m){m[1]=m[1].1G();o 1e 2g("[@#{1}]").2b(m)},4N:q(m){m[1]=m[1].1G();m[3]=m[5]||m[6];o 1e 2g(O.1V.5y[m[2]]).2b(m)},5z:q(m){G h=O.1V.1H[m[1]];E(!h)o\'\';E(J.1M(h))o h(m);o 1e 2g(O.1V.1H[m[1]]).2b(m)},5y:{\'=\':"[@#{1}=\'#{3}\']",\'!=\':"[@#{1}!=\'#{3}\']",\'^=\':"[eU-97(@#{1}, \'#{3}\')]",\'$=\':"[4l(@#{1}, (5O-M(@#{1}) - 5O-M(\'#{3}\') + 1))=\'#{3}\']",\'*=\':"[5x(@#{1}, \'#{3}\')]",\'~=\':"[5x(1z(\' \', @#{1}, \' \'), \' #{3} \')]",\'|=\':"[5x(1z(\'-\', @#{1}, \'-\'), \'-#{3}-\')]"},1H:{\'2C-1r\':\'[3G(8a-3F::*)]\',\'1Q-1r\':\'[3G(5v-3F::*)]\',\'5A-1r\':\'[3G(8a-3F::* 89 5v-3F::*)]\',\'4n\':"[6D(*) = 0 8b (6D(2U()) = 0 89 eV(2U(), \' \\t\\r\\n\', \'\') = \'\')]",\'2K\':"[@2K]",\'2z\':"[@2z]",\'aO\':"[3G(@2z)]",\'3G\':q(m){G e=m[6],p=O.5u,x=O.1V,3h,v;G a=[];1q(e&&3h!=e&&(/\\S/).2d(e)){3h=e;N(G i 1s p){E(m=e.1k(p[i])){v=J.1M(x[i])?x[i](m):1e 2g(x[i]).2b(m);a.14("("+v.4l(1,v.M-1)+")");e=e.1x(m[0],\'\');1F}}}o"[3G("+a.1P(" 8b ")+")]"},\'1y-1r\':q(m){o O.1V.1H.1y("(6D(./8a-3F::*) + 1) ",m)},\'1y-1Q-1r\':q(m){o O.1V.1H.1y("(6D(./5v-3F::*) + 1) ",m)},\'1y-1U-1n\':q(m){o O.1V.1H.1y("1v() ",m)},\'1y-1Q-1U-1n\':q(m){o O.1V.1H.1y("(1Q() + 1 - 1v()) ",m)},\'2C-1U-1n\':q(m){m[6]="1";o O.1V.1H[\'1y-1U-1n\'](m)},\'1Q-1U-1n\':q(m){m[6]="1";o O.1V.1H[\'1y-1Q-1U-1n\'](m)},\'5A-1U-1n\':q(m){G p=O.1V.1H;o p[\'2C-1U-1n\'](m)+p[\'1Q-1U-1n\'](m)},1y:q(c,m){G d,4c=m[6],8c;E(4c==\'aP\')4c=\'2n+0\';E(4c==\'aQ\')4c=\'2n+1\';E(d=4c.1k(/^(\\d+)$/))o\'[\'+c+"= "+d[1]+\']\';E(d=4c.1k(/^(-?\\d*)?n(([+-])(\\d+))?/)){E(d[1]=="-")d[1]=-1;G a=d[1]?3T(d[1]):1;G b=d[2]?3T(d[2]):0;8c="[((#{8d} - #{b}) eW #{a} = 0) 8b "+"((#{8d} - #{b}) 2k #{a} >= 0)]";o 1e 2g(8c).2b({8d:c,a:a,b:b})}}}},54:{1h:\'n = h.1h(n, r, "#{1}", c); c = 1d;\',1J:\'n = h.1J(n, r, "#{1}", c); c = 1d;\',29:\'n = h.29(n, r, "#{1}", c); c = 1d;\',4M:\'n = h.4M(n, r, "#{1}", c); c = 1d;\',4N:q(m){m[3]=(m[5]||m[6]);o 1e 2g(\'n = h.4N(n, r, "#{1}", "#{3}", "#{2}", c); c = 1d;\').2b(m)},5z:q(m){E(m[6])m[6]=m[6].1x(/"/g,\'\\\\"\');o 1e 2g(\'n = h.5z(n, "#{1}", "#{6}", r, c); c = 1d;\').2b(m)},3E:\'c = "3E";\',1r:\'c = "1r";\',42:\'c = "42";\',5w:\'c = "5w";\'},5u:{5w:/^\\s*~\\s*/,1r:/^\\s*>\\s*/,42:/^\\s*\\+\\s*/,3E:/^\\s/,1h:/^\\s*(\\*|[\\w\\-]+)(\\b|$)?/,29:/^#([\\w\\-\\*]+)(\\b|$)/,1J:/^\\.([\\w\\-\\*]+)(\\b|$)/,5z:/^:((2C|1Q|1y|1y-1Q|5A)(-1r|-1U-1n)|4n|2K|(en|eX)eY|3G)(\\((.*?)\\))?(\\b|$|(?=\\s|[:+~>]))/,4M:/^\\[([\\w]+)\\]/,4N:/\\[((?:[\\w-]*:)?[\\w-]+)\\s*(?:([!^$*~|]?=)\\s*(([\'"])([^\\4]*?)\\4|([^\'"][^\\]]*?)))?\\]/},87:{1h:q(a,b){o b[1].2f()==a.1h.2f()},1J:q(a,b){o I.6i(a,b[1])},29:q(a,b){o a.29===b[1]},4M:q(a,b){o I.2J(a,b[1])},4N:q(a,b){G c=I.43(a,b[1]);o c&&O.5y[b[2]](c,b[5]||b[6])}},1C:{1z:q(a,b){N(G i=0,L;L=b[i];i++)a.14(L);o a},6E:q(a){G b=Y.2q;N(G i=0,L;L=a[i];i++)L.2M=b;o a},4d:q(a){N(G i=0,L;L=a[i];i++)L.2M=3k;o a},50:q(a,b,c){a.2M=Y.2q;E(b){N(G d=a.2o,i=d.M-1,j=1;i>=0;i--){G e=d[i];E(e.2t==1&&(!c||e.2M))e.6F=j++}}19{N(G i=0,j=1,d=a.2o;e=d[i];i++)E(e.2t==1&&(!c||e.2M))e.6F=j++}},85:q(a){E(a.M==0)o a;G b=[],n;N(G i=0,l=a.M;i<l;i++)E(!(n=a[i]).2M){n.2M=Y.2q;b.14(I.U(n))}o O.1C.4d(b)},3E:q(a){G h=O.1C;N(G i=0,15=[],L;L=a[i];i++)h.1z(15,L.3i(\'*\'));o 15},1r:q(a){G h=O.1C;N(G i=0,15=[],L;L=a[i];i++){N(G j=0,1r;1r=L.2o[j];j++)E(1r.2t==1&&1r.1h!=\'!\')15.14(1r)}o 15},42:q(a){N(G i=0,15=[],L;L=a[i];i++){G b=C.5k(L);E(b)15.14(b)}o 15},5w:q(a){G h=O.1C;N(G i=0,15=[],L;L=a[i];i++)h.1z(15,I.5i(L));o 15},5k:q(a){1q(a=a.3x)E(a.2t==1)o a;o 17},5j:q(a){1q(a=a.9X)E(a.2t==1)o a;o 17},1h:q(a,b,c,d){G e=c.2f();G f=[],h=O.1C;E(a){E(d){E(d=="3E"){N(G i=0,L;L=a[i];i++)h.1z(f,L.3i(c));o f}19 a=C[d](a);E(c=="*")o a}N(G i=0,L;L=a[i];i++)E(L.1h.2f()===e)f.14(L);o f}19 o b.3i(c)},29:q(a,b,c,d){G e=$(c),h=O.1C;E(!e)o[];E(!a&&b==V)o[e];E(a){E(d){E(d==\'1r\'){N(G i=0,L;L=a[i];i++)E(e.1A==L)o[e]}19 E(d==\'3E\'){N(G i=0,L;L=a[i];i++)E(I.6j(e,L))o[e]}19 E(d==\'42\'){N(G i=0,L;L=a[i];i++)E(O.1C.5j(e)==L)o[e]}19 a=h[d](a)}N(G i=0,L;L=a[i];i++)E(L==e)o[e];o[]}o(e&&I.6j(e,b))?[e]:[]},1J:q(a,b,c,d){E(a&&d)a=C[d](a);o O.1C.aR(a,b,c)},aR:q(a,b,c){E(!a)a=O.1C.3E([b]);G d=\' \'+c+\' \';N(G i=0,15=[],L,5B;L=a[i];i++){5B=L.1J;E(5B.M==0)2F;E(5B==c||(\' \'+5B+\' \').1p(d))15.14(L)}o 15},4M:q(a,b,c,d){E(!a)a=b.3i("*");E(a&&d)a=C[d](a);G e=[];N(G i=0,L;L=a[i];i++)E(I.2J(L,c))e.14(L);o e},4N:q(a,b,c,d,e,f){E(!a)a=b.3i("*");E(a&&f)a=C[f](a);G g=O.5y[e],15=[];N(G i=0,L;L=a[i];i++){G h=I.43(L,c);E(h===17)2F;E(g(h,d))15.14(L)}o 15},5z:q(a,b,c,d,e){E(a&&e)a=C[e](a);E(!a)a=d.3i("*");o O.1H[b](a,c,d)}},1H:{\'2C-1r\':q(a,b,c){N(G i=0,15=[],L;L=a[i];i++){E(O.1C.5j(L))2F;15.14(L)}o 15},\'1Q-1r\':q(a,b,c){N(G i=0,15=[],L;L=a[i];i++){E(O.1C.5k(L))2F;15.14(L)}o 15},\'5A-1r\':q(a,b,c){G h=O.1C;N(G i=0,15=[],L;L=a[i];i++)E(!h.5j(L)&&!h.5k(L))15.14(L);o 15},\'1y-1r\':q(a,b,c){o O.1H.1y(a,b,c)},\'1y-1Q-1r\':q(a,b,c){o O.1H.1y(a,b,c,1f)},\'1y-1U-1n\':q(a,b,c){o O.1H.1y(a,b,c,1d,1f)},\'1y-1Q-1U-1n\':q(a,b,c){o O.1H.1y(a,b,c,1f,1f)},\'2C-1U-1n\':q(a,b,c){o O.1H.1y(a,"1",c,1d,1f)},\'1Q-1U-1n\':q(a,b,c){o O.1H.1y(a,"1",c,1f,1f)},\'5A-1U-1n\':q(a,b,c){G p=O.1H;o p[\'1Q-1U-1n\'](p[\'2C-1U-1n\'](a,b,c),b,c)},aS:q(a,b,d){E(a==0)o b>0?[b]:[];o $R(1,d).2E([],q(c,i){E(0==(i-b)%a&&(i-b)/a>=0)c.14(i);o c})},1y:q(c,d,e,f,g){E(c.M==0)o[];E(d==\'aP\')d=\'2n+0\';E(d==\'aQ\')d=\'2n+1\';G h=O.1C,15=[],8e=[],m;h.6E(c);N(G i=0,L;L=c[i];i++){E(!L.1A.2M){h.50(L.1A,f,g);8e.14(L.1A)}}E(d.1k(/^\\d+$/)){d=3T(d);N(G i=0,L;L=c[i];i++)E(L.6F==d)15.14(L)}19 E(m=d.1k(/^(-?\\d*)?n(([+-])(\\d+))?/)){E(m[1]=="-")m[1]=-1;G a=m[1]?3T(m[1]):1;G b=m[2]?3T(m[2]):0;G k=O.1H.aS(a,b,c.M);N(G i=0,L,l=k.M;L=c[i];i++){N(G j=0;j<l;j++)E(L.6F==k[j])15.14(L)}}h.4d(c);h.4d(8e);o 15},\'4n\':q(a,b,c){N(G i=0,15=[],L;L=a[i];i++){E(L.1h==\'!\'||(L.4x&&!L.3t.1k(/^\\s*$/)))2F;15.14(L)}o 15},\'3G\':q(a,b,c){G h=O.1C,eZ,m;G d=1e O(b).6B(c);h.6E(d);N(G i=0,15=[],L;L=a[i];i++)E(!L.2M)15.14(L);h.4d(d);o 15},\'aO\':q(a,b,c){N(G i=0,15=[],L;L=a[i];i++)E(!L.2z)15.14(L);o 15},\'2z\':q(a,b,c){N(G i=0,15=[],L;L=a[i];i++)E(L.2z)15.14(L);o 15},\'2K\':q(a,b,c){N(G i=0,15=[],L;L=a[i];i++)E(L.2K)15.14(L);o 15}},5y:{\'=\':q(a,v){o a==v},\'!=\':q(a,v){o a!=v},\'^=\':q(a,v){o a.77(v)},\'$=\':q(a,v){o a.91(v)},\'*=\':q(a,v){o a.1p(v)},\'~=\':q(a,v){o(\' \'+a+\' \').1p(\' \'+v+\' \')},\'|=\':q(a,v){o(\'-\'+a.2f()+\'-\').1p(\'-\'+v.2f()+\'-\')}},32:q(a){G b=[];a.8S(/(([\\w#:.~>+()\\s-]+|\\*|\\[.*?\\])+)\\s*(,|$)/,q(m){b.14(m[1].2T())});o b},aT:q(a,b){G c=$$(b),h=O.1C;h.6E(c);N(G i=0,15=[],1u;1u=a[i];i++)E(1u.2M)15.14(1u);h.4d(c);o 15},4y:q(a,b,c){E(J.3Q(b)){c=b;b=1d}o O.aT(a,b||\'*\')[c||0]},6f:q(a,b){b=O.32(b.1P(\',\'));G c=[],h=O.1C;N(G i=0,l=b.M,8f;i<l;i++){8f=1e O(b[i].2T());h.1z(c,8f.6B(a))}o(l>1)?h.85(c):c}});E(Y.1w.2N){J.U(O.1C,{1z:q(a,b){N(G i=0,L;L=b[i];i++)E(L.1h!=="!")a.14(L);o a},4d:q(a){N(G i=0,L;L=a[i];i++)L.7N(\'2M\');o a}})}q $$(){o O.6f(V,$A(1c))}G 1j={8g:q(a){$(a).8g();o a},aU:q(c,d){E(2R d!=\'2D\')d={6G:!!d};19 E(J.1X(d.6G))d.6G=1f;G e,1g,8h=1d,4e=d.4e;G f=c.2E({},q(a,b){E(!b.2z&&b.21){e=b.21;1g=$(b).2j();E(1g!=17&&(b.1n!=\'4e\'||(!8h&&4e!==1d&&(!4e||e==4e)&&(8h=1f)))){E(e 1s a){E(!J.3n(a[e]))a[e]=[a[e]];a[e].14(1g)}19 a[e]=1g}}o a});o d.6G?f:J.3m(f)}};1j.W={5C:q(a,b){o 1j.aU(1j.4O(a),b)},4O:q(c){o $A($(c).3i(\'*\')).2E([],q(a,b){E(1j.I.4P[b.1h.1G()])a.14(I.U(b));o a})},f0:q(a,b,c){a=$(a);G d=a.3i(\'6H\');E(!b&&!c)o $A(d).2e(I.U);N(G i=0,8i=[],M=d.M;i<M;i++){G e=d[i];E((b&&e.1n!=b)||(c&&e.21!=c))2F;8i.14(I.U(e))}o 8i},8j:q(a){a=$(a);1j.4O(a).5P(\'8j\');o a},8k:q(a){a=$(a);1j.4O(a).5P(\'8k\');o a},aV:q(b){G c=$(b).4O().4p(q(a){o\'6n\'!=a.1n&&!a.2z});G d=c.4p(q(a){o a.2J(\'6t\')&&a.6t>=0}).9e(q(a){o a.6t}).2C();o d?d:c.7f(q(a){o[\'6H\',\'20\',\'8l\'].1p(a.1h.1G())})},f1:q(a){a=$(a);a.aV().aW();o a},2V:q(a,b){a=$(a),b=J.1Z(b||{});G c=b.2v,4J=a.43(\'4J\')||\'\';E(4J.3S())4J=1i.68.ap;b.2v=a.5C(1f);E(c){E(J.2l(c))c=c.5U();J.U(b.2v,c)}E(a.2J(\'28\')&&!b.28)b.28=a.28;o 1e 1t.3V(4J,b)}};1j.I={8m:q(a){$(a).8m();o a},20:q(a){$(a).20();o a}};1j.I.W={5C:q(a){a=$(a);E(!a.2z&&a.21){G b=a.2j();E(b!=3k){G c={};c[a.21]=b;o J.3m(c)}}o\'\'},2j:q(a){a=$(a);G b=a.1h.1G();o 1j.I.4P[b](a)},f2:q(a,b){a=$(a);G c=a.1h.1G();1j.I.4P[c](a,b);o a},9h:q(a){$(a).1g=\'\';o a},f3:q(a){o $(a).1g!=\'\'},aW:q(a){a=$(a);1N{a.8m();E(a.20&&(a.1h.1G()!=\'6H\'||![\'8n\',\'8g\',\'4e\'].1p(a.1n)))a.20()}1Y(e){}o a},8j:q(a){a=$(a);a.f4();a.2z=1f;o a},8k:q(a){a=$(a);a.2z=1d;o a}};G f5=1j.I;G $F=1j.I.W.2j;1j.I.4P={6H:q(a,b){4h(a.1n.1G()){1O\'aX\':1O\'aY\':o 1j.I.4P.aZ(a,b);5r:o 1j.I.4P.8l(a,b)}},aZ:q(a,b){E(J.1X(b))o a.2K?a.1g:17;19 a.2K=!!b},8l:q(a,b){E(J.1X(b))o a.1g;19 a.1g=b},20:q(a,b){E(J.1X(b))o C[a.1n==\'20-f6\'?\'b0\':\'b1\'](a);19{G c,1g,b2=!J.3n(b);N(G i=0,M=a.M;i<M;i++){c=a.1b[i];1g=C.6I(c);E(b2){E(1g==b){c.8o=1f;o}}19 c.8o=b.1p(1g)}}},b0:q(a){G b=a.f7;o b>=0?C.6I(a.1b[b]):17},b1:q(a){G b,M=a.M;E(!M)o 17;N(G i=0,b=[];i<M;i++){G c=a.1b[i];E(c.8o)b.14(C.6I(c))}o b},6I:q(a){o I.U(a).2J(\'1g\')?a.1g:a.2U}};3P.8p=1E.1L(8N,{22:q($2Y,b,c,d){$2Y(d,c);C.1u=$(b);C.3H=C.2j()},6Y:q(){G a=C.2j();E(J.2l(C.3H)&&J.2l(a)?C.3H!=a:1B(C.3H)!=1B(a)){C.4W(C.1u,a);C.3H=a}}});1j.I.b3=1E.1L(3P.8p,{2j:q(){o 1j.I.2j(C.1u)}});1j.b3=1E.1L(3P.8p,{2j:q(){o 1j.5C(C.1u)}});3P.5D=1E.1L({22:q(a,b){C.1u=$(a);C.4W=b;C.3H=C.2j();E(C.1u.1h.1G()==\'6S\')C.b4();19 C.4Y(C.1u)},8q:q(){G a=C.2j();E(C.3H!=a){C.4W(C.1u,a);C.3H=a}},b4:q(){1j.4O(C.1u).1l(C.4Y,C)},4Y:q(a){E(a.1n){4h(a.1n.1G()){1O\'aX\':1O\'aY\':1m.3I(a,\'f8\',C.8q.1o(C));1F;5r:1m.3I(a,\'f9\',C.8q.1o(C));1F}}}});1j.I.5D=1E.1L(3P.5D,{2j:q(){o 1j.I.2j(C.1u)}});1j.5D=1E.1L(3P.5D,{2j:q(){o 1j.5C(C.1u)}});E(!1i.1m)G 1m={};J.U(1m,{fa:8,fb:9,fc:13,fd:27,fe:37,ff:38,fg:39,fh:40,fi:46,fj:36,fk:35,fl:33,fm:34,fn:45,5e:{},8r:q(a){G b;4h(a.1n){1O\'fo\':b=a.fp;1F;1O\'fq\':b=a.2x;1F;5r:o 17}o I.U(b)}});1m.W=(q(){G e;E(Y.1w.2N){G f={0:1,1:4,2:2};e=q(a,b){o a.8n==f[b]}}19 E(Y.1w.3j){e=q(a,b){4h(b){1O 0:o a.6J==1&&!a.b5;1O 1:o a.6J==1&&a.b5;5r:o 1d}}}19{e=q(a,b){o a.6J?(a.6J===b+1):(a.8n===b)}}o{fr:q(a){o e(a,0)},fs:q(a){o e(a,1)},ft:q(a){o e(a,2)},1u:q(a){G b=1m.U(a).b6;o I.U(b.2t==5d.9O?b.1A:b)},4y:q(a,b){G c=1m.1u(a);E(!b)o c;G d=[c].1z(c.7I());o O.4y(d,b,0)},6K:q(a){o{x:a.b7||(a.fu+(V.3D.3A||V.1S.3A)),y:a.b8||(a.fv+(V.3D.3z||V.1S.3z))}},fw:q(a){o 1m.6K(a).x},fx:q(a){o 1m.6K(a).y},6Z:q(a){1m.U(a);a.b9();a.ba();a.fy=1f}}})();1m.U=(q(){G c=J.4g(1m.W).2E({},q(m,a){m[a]=1m.W[a].3o();o m});E(Y.1w.2N){J.U(c,{ba:q(){C.fz=1f},b9:q(){C.fA=1d},1W:q(){o"[2D 1m]"}});o q(a){E(!a)o 1d;E(a.6y)o a;a.6y=Y.2q;G b=1m.6K(a);J.U(a,{b6:a.fB,8r:1m.8r(a),b7:b.x,b8:b.y});o J.U(a,c)}}19{1m.18=1m.18||V.5E("bb").3M;J.U(1m.18,c);o Y.K}})();J.U(1m,(q(){G h=1m.5e;q 8s(a){E(a.8t)o a.8t[0];1c.4k.29=1c.4k.29||1;o a.8t=[++1c.4k.29]}q 8u(a){E(a&&a.1p(\':\'))o"bc";o a}q 6L(a){o h[a]=h[a]||{}}q 6M(a,b){G c=6L(a);o c[b]=c[b]||[]}q bd(b,d,e){G f=8s(b);G c=6M(f,d);E(c.4q("6N").1p(e))o 1d;G g=q(a){E(!1m||!1m.U||(a.8v&&a.8v!=d))o 1d;1m.U(a);e.7E(b,a)};g.6N=e;c.14(g);o g}q 8w(b,d,e){G c=6M(b,d);o c.7f(q(a){o a.6N==e})}q be(a,b,d){G c=6L(a);E(!c[b])o 1d;c[b]=c[b].56(8w(a,b,d))}q bf(){N(G a 1s h)N(G b 1s h[a])h[a][b]=17}E(1i.5J){1i.5J("ar",bf)}o{3I:q(a,b,c){a=$(a);G d=8u(b);G e=bd(a,b,c);E(!e)o a;E(a.6O){a.6O(d,e,1d)}19{a.5J("4u"+d,e)}o a},4f:q(b,c,d){b=$(b);G e=8s(b),21=8u(c);E(!d&&c){6M(e,c).1l(q(a){b.4f(c,a.6N)});o b}19 E(!c){J.4g(6L(e)).1l(q(a){b.4f(a)});o b}G f=8w(e,c,d);E(!f)o b;E(b.bg){b.bg(21,f,1d)}19{b.fC("4u"+21,f)}be(e,c,d);o b},4Q:q(a,b,c){a=$(a);E(a==V&&V.5E&&!a.bh)a=V.3D;G d;E(V.5E){d=V.5E("bb");d.fD("bc",1f,1f)}19{d=V.fE();d.bi="fF"}d.8v=b;d.fG=c||{};E(V.5E){a.bh(d)}19{a.fH(d.bi,d)}o 1m.U(d)}}})());J.U(1m,1m.W);I.4V({4Q:1m.4Q,3I:1m.3I,4f:1m.4f});J.U(V,{4Q:I.W.4Q.3o(),3I:I.W.3I.3o(),4f:I.W.4f.3o(),5F:1d});(q(){G a;q 5G(){E(V.5F)o;E(a)1i.8P(a);V.4Q("fI:5F");V.5F=1f}E(V.6O){E(Y.1w.3j){a=1i.8O(q(){E(/5F|bj/.2d(V.2W))5G()},0);1m.3I(1i,"fJ",5G)}19{V.6O("fK",5G,1d)}}19{V.5l("<4T 29=bk 3p aq=//:><\\/4T>");$("bk").63=q(){E(C.2W=="bj"){C.63=17;5G()}}}})();2S.3m=J.3m;G fL={3e:I.9P};I.W.fM=I.W.6j;G fN={fO:q(a,b){o I.2w(a,{7H:b})},fP:q(a,b){o I.2w(a,{2h:b})},fQ:q(a,b){o I.2w(a,{41:b})},fR:q(a,b){o I.2w(a,{6c:b})}};G $2F=1e fS(\'"3l $2F" fT fU, fV "o" fW\');G 8x={bl:1d,8y:q(){C.bm=1i.aH||V.3D.3A||V.1S.3A||0;C.bn=1i.aI||V.3D.3z||V.1S.3z||0},fX:q(a,x,y){E(C.bl)o C.bo(a,x,y);C.5H=x;C.5I=y;C.2i=I.44(a);o(y>=C.2i[1]&&y<C.2i[1]+a.4F&&x>=C.2i[0]&&x<C.2i[0]+a.4E)},bo:q(a,x,y){G b=I.7W(a);C.5H=x+b[0]-C.bm;C.5I=y+b[1]-C.bn;C.2i=I.44(a);o(C.5I>=C.2i[1]&&C.5I<C.2i[1]+a.4F&&C.5H>=C.2i[0]&&C.5H<C.2i[0]+a.4E)},fY:q(a,b){E(!a)o 0;E(a==\'fZ\')o((C.2i[1]+b.4F)-C.5I)/b.4F;E(a==\'g0\')o((C.2i[0]+b.4E)-C.5H)/b.4E},44:I.W.44,5p:I.W.5p,7U:q(a){8x.8y();o I.7U(a)},7V:q(a){8x.8y();o I.7V(a)},g1:I.W.7W,3f:I.W.4I,g2:I.W.5q,1Z:q(a,b,c){c=c||{};o I.af(b,a,c)}};E(!V.6P)V.6P=q(f){q 8z(a){o a.3S()?17:"[5x(1z(\' \', @5h, \' \'), \' "+a+" \')]"}f.6P=Y.2P.5L?q(a,b){b=b.24().2T();G c=/\\s/.2d(b)?$w(b).2e(8z).1P(\'\'):8z(b);o c?V.7D(\'.//*\'+c,a):[]}:q(b,c){c=c.24().2T();G d=[],5m=(/\\s/.2d(c)?$w(c):17);E(!5m&&!c)o d;G e=$(b).3i(\'*\');c=\' \'+c+\' \';N(G i=0,1r,cn;1r=e[i];i++){E(1r.1J&&(cn=\' \'+1r.1J+\' \')&&(cn.1p(c)||(5m&&5m.7d(q(a){o!a.24().3S()&&cn.1p(\' \'+a+\' \')}))))d.14(I.U(1r))}o d};o q(a,b){o $(b||V.1S).6P(a)}}(I.W);I.6h=1E.1L();I.6h.18={22:q(a){C.1u=$(a)},3c:q(b){C.1u.1J.32(/\\s+/).20(q(a){o a.M>0}).3c(b)},58:q(a){C.1u.1J=a},g3:q(a){E(C.1p(a))o;C.58($A(C).1z(a).1P(\' \'))},9S:q(a){E(!C.1p(a))o;C.58($A(C).56(a).1P(\' \'))},24:q(){o $A(C).1P(\' \')}};J.U(I.6h.18,26);I.4V();',62,996,'||||||||||||||||||||||||return||function||||||||||||this||if||var||Element|Object||node|length|for|Selector||||||extend|document|Methods||Prototype||||||push|results||null|prototype|else|style|options|arguments|false|new|true|value|tagName|window|Form|match|each|Event|type|bind|include|while|child|in|Ajax|element|position|Browser|replace|nth|concat|parentNode|String|handlers|getStyle|Class|break|toLowerCase|pseudos|Array|className|_getEv|create|isFunction|try|case|join|last|transport|body|width|of|xpath|inspect|isUndefined|catch|clone|select|name|initialize||toString|values|Enumerable||method|id|valueL|evaluate|args|test|map|toUpperCase|Template|top|offset|getValue|div|isString|gsub||childNodes|px|emptyFunction|klass|toJSON|nodeType|toArray|parameters|insert|toElement|height|disabled|ByTag|apply|first|object|inject|continue|_attributeTranslations|opacity|left|hasAttribute|checked|matcher|_countedByPrototype|IE|indexOf|BrowserFeatures|createElement|typeof|Hash|strip|text|request|readyState|expression|super|isElement||toHTML|split||||||||RegExp|stripScripts|_each|response|display|offsetParent|ps|le|getElementsByTagName|WebKit|undefined|throw|toQueryString|isArray|methodize|defer|toPaddedString|source|slice|innerHTML|_object|onComplete|responseText|nextSibling|names|scrollTop|scrollLeft|tags|table|documentElement|descendant|sibling|not|lastValue|observe|Opera|navigator|userAgent|__proto__|shift|wrap|Abstract|isNumber|evalScripts|blank|Number|update|Request|url|dispatchException|success|decay||bottom|adjacent|readAttribute|cumulativeOffset|||_overflow|offsetTop|offsetLeft|_returnOffset|_cache|formula|unmark|submit|stopObserving|keys|switch|interpret|timer|callee|substring|evalJSON|empty|appendChild|findAll|pluck|filter|key|Responders|on|getHeader|_insertionTranslations|firstChild|findElement|getDimensions|nextAncestor|parseFloat|setStyle|setOpacity|offsetWidth|offsetHeight|absolute|static|getOffsetParent|action|tbody|Heading|attrPresence|attr|getElements|Serializers|fire|ElementExtensions|HTMLElement|script|properties|addMethods|callback|frequency|registerCallback|onTimerEvent|index|capitalize|_|expr|criteria|reverse|without|toObject|set|start|responders|post|getStatus|Node|cache|writeAttribute|removeChild|class|nextSiblings|previousElementSibling|nextElementSibling|write|classNames|sourceIndex|relative|positionedOffset|viewportOffset|default|_flag|property|patterns|following|laterSibling|contains|operators|pseudo|only|nodeClassName|serialize|EventObserver|createEvent|loaded|fireContentLoadedEvent|xcomp|ycomp|attachEvent|Gecko|XPath|SpecificElementExtensions|ScriptFragment|string|invoke|curry|currentlyExecuting|eval|escapeHTML|toQueryParams|times|charAt|detect|pair|dispatch|onCreate|asynchronous|application|onreadystatechange|status|headerJSON|isSameOrigin|port|location|container|insertion|none|after|_getContentFromAnonymousElement|recursivelyCollect|findChildElements|read|ClassNames|hasClassName|descendantOf|cssFloat|auto|00001|hidden|right|border|padding|title|_getAttr|tabIndex|insertBefore|TBODY|tr|Simulated|_extendedByPrototype|refresh|copy|findElements|token|count|mark|nodeIndex|hash|input|optionValue|which|pointer|getCacheForID|getWrappersForEventName|handler|addEventListener|getElementsByClassName|Version|opera|form|superclass|isHash|Function|delay|_methodized|execute|stop|prepareReplacement|nodeValue|decodeURIComponent|succ|camelize|len|unfilterJSON|startsWith|lastIndexOf|toTemplateReplacements|slices|array|collect|all|falses|find|_reverse|toQueryPair|get|delete|end|activeRequestCount|Base|encoding|evalJS|_complete|Response|respondToReadyState|onStateChange|Content|Complete|protocol|domain|getResponseHeader|statusText|getAllResponseHeaders|failure|updater|elements|_getElementsByXPath|call|visible|replaceChild|before|ancestors|previousSiblings|self|attributes|getAttribute|removeAttribute|float|cssText|styleFloat|visibility|_madePositioned|overflow|absolutize|relativize|cumulativeScrollOffset|zoom|currentStyle|alpha|stripAlpha|has|TD|TableSection|HTML|unique|tokens|assertions|matches|or|preceding|and|predicate|fragment|indexed|selector|reset|submitted|matchingInputs|disable|enable|textarea|focus|button|selected|TimedObserver|onElementEvent|relatedTarget|getEventID|_prototypeEventID|getDOMEventName|eventName|findWrapper|Position|prepare|iter|KHTML|MobileSafari|Safari|JSONFilter|subclasses|valueOf|argumentNames|instanceof|timeout|1000|Try|these|escape|PeriodicalExecuter|setInterval|clearInterval|specialChar|sub|scan|stripTags|gi|img|extractScripts|unescapeHTML|charCodeAt|isJSON|JSON|endsWith|interpolate|amp|lt|gt|createTextNode|with|template|pattern|Pattern|exec|eachSlice|any|sortBy|size|from|clear|flatten|uniq|forEach|arrayLength|encodeURIComponent|ObjectRange|exclusive|getTransport|XMLHttpRequest|ActiveXObject|XMLHTTP|register|contentType|setRequestHeaders|overrideMimeType|xml|2005|requestHeaders|Events|force|evalResponse|onException|getStatusText|_getHeaderJSON|responseXML|_getResponseJSON|sanitizeJSON|Updater|updateContent|updateComplete|lastText|ELEMENT_NODE|TEXT_NODE|toggle|hide|show|remove|attribute|descendants|firstDescendant|immediateDescendants|previousSibling|next|identify|counter|setAttribute|getHeight|getWidth|addClassName|removeClassName|compareDocumentPosition|scrollTo|clientWidth|clientHeight|BODY|_originalLeft|_originalTop|_originalWidth|_originalHeight|clonePosition|setLeft|setTop|setWidth|setHeight|htmlFor|parseInt|100|_getAttrNode|getAttributeNode|href|src|onunload||IMG|outerHTML|TR|td|SELECT|THEAD|TFOOT|TH|TEXTAREA|findDOMClass|Mod|TableCol|TableCell|client|pageXOffset|pageYOffset|compileMatcher|shouldUseXPath|compileXPathMatcher|root|local|enabled|even|odd|byClassName|getIndices|matchElements|serializeElements|findFirstElement|activate|checkbox|radio|inputSelector|selectOne|selectMany|single|Observer|registerFormCallbacks|metaKey|target|pageX|pageY|preventDefault|stopPropagation|HTMLEvents|dataavailable|createWrapper|destroyWrapper|destroyCache|removeEventListener|dispatchEvent|eventType|complete|__onDOMContentLoaded|includeScrollOffsets|deltaX|deltaY|withinIncludingScrolloffsets|AppleWebKit|Apple|Mobile|secure|constructor|RangeError|unknown|boolean|splice|number|bindAsEventListener|event|setTimeout|01|Date|getUTCFullYear|getUTCMonth|getUTCDate|getUTCHours|getUTCMinutes|getUTCSeconds|finally|truncate|im|data|fromCharCode|underscore|dasherize|x00|x1f|u00|Eaeflnr|SyntaxError|Badly|formed|parseQuery|grep|inGroupsOf|max|min|partition|reject|sort|zip|pop|member|entries|every|some|NodeList|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|html|charset|Connection|close|setRequestHeader|200|300|Success|Failure|java|ecma|https|Uninitialized|Loading|Loaded|Interactive|responseJSON|getAllHeaders|json|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|normal|cellpadding|cellPadding|cellspacing|cellSpacing|colSpan|rowSpan|vAlign|dateTime|accessKey|encType|maxLength|readOnly|longDesc|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|getScrollOffsets|starts|translate|mod|dis|abled|selectorType|getInputs|focusFirstElement|setValue|present|blur|Field|one|selectedIndex|click|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|clientY|pointerX|pointerY|stopped|cancelBubble|returnValue|srcElement|detachEvent|initEvent|createEventObject|ondataavailable|memo|fireEvent|dom|load|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.prototype = {
 initialize : function(form, options){
 this.form = $(form);
 if (!this.form) {
 return;
 }
 this.options = Object.extend({
 onSubmit : true,
 stopOnFirst : false,
 immediate : false,
 focusOnError : true,
 useTitles : false,
 onFormValidate : function(result, form) {},
 onElementValidate : function(result, elm) {}
 }, options || {});
 if(this.options.onSubmit) Event.observe(this.form,'submit',this.onSubmit.bind(this),false);
 if(this.options.immediate) {
 var useTitles = this.options.useTitles;
 var callback = this.options.onElementValidate;
 Form.getElements(this.form).each(function(input) { // Thanks Mike!
 Event.observe(input, 'blur', function(ev) { Validation.validate(Event.element(ev),{useTitle : useTitles, onElementValidate : callback}); });
 });
 }
 },
 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.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');
 },
 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');
 }
 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');
 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);
 advice.hide();
 elm[prop] = '';
 }
 elm.removeClassName('validation-failed');
 elm.removeClassName('validation-passed');
 });
 },
 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-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-cpassword', 'Please make sure your passwords match.', function(v) {
 var pass = $('password') ? $('password') : $$('.validate-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');
 var error = 1;
 for( i in inputs ) {
 if( inputs[i].checked == true && inputs[i].name == elm.name ) {
 error = 0;
 }
 }

 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;
 }

 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');
 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 changeMainImage(path,divId)
{
 document.getElementById(divId).innerHTML = '<img src="'+path+'" style="max-width: 400px; max-height: 300px; left: 0px; top: 0px;" >';
}

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)
 }
 );
 },

 _selectAutocompleteItem : function(element){
 if(element.title){
 this.field.value = element.title;
 }
 this.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.className){
 Element.addClassName(element, this.highlightClass);
 }
 },

 elementOnBlur: function(event){
 var element = Event.findElement(event, 'fieldset');
 if(element && element.className){
 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){
 if(elem.parentNode){
 var marks = Element.select(elem.parentNode, '.required');
 if(marks[0]){
 display ? marks[0].show() : marks[0].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 Cookies.getCookieVal(j);
 i = document.cookie.indexOf(" ", i) + 1;
 if(i == 0)
 break;
 }
 return null;
};

Mage.Cookies.clear = function(name) {
 if(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));
};
