

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}('D 12={5z:\'1.5.1\',1Z:{3X:!!(1j.3Y&&!1j.4C),5A:!!1j.4C,3r:3Z.41.3s(\'9m/\')>-1,4D:3Z.41.3s(\'4D\')>-1&&3Z.41.3s(\'6Y\')==-1},3b:{5B:!!11.25,42:!!1j.43,5C:(11.2y(\'2d\').44!==11.2y(\'5D\').44)},4E:\'<5E[^>]*>([\\9n-\\9o]*?)</5E>\',6Z:/^\\/\\*-9p-\\s*(.*)\\s*\\*\\/\\s*$/,2J:o(){},K:o(x){B x}};D 1C={1D:o(){B o(){7.26.2l(7,17)}}};D 1O=V N();N.M=o(a,b){J(D c 1t b){a[c]=b[c]}B a};N.M(N,{1H:o(a){1P{C(a===1l)B\'1l\';C(a===18)B\'18\';B a.1H?a.1H():a.28()}1V(e){C(e 5F 9q)B\'...\';2z e;}},1Q:o(a){D b=1m a;45(b){1I\'1l\':1I\'o\':1I\'9r\':B;1I\'9s\':B a.28()}C(a===18)B\'18\';C(a.1Q)B a.1Q();C(a.5G===11)B;D c=[];J(D d 1t a){D e=N.1Q(a[d]);C(e!==1l)c.O(d.1Q()+\': \'+e)}B\'{\'+c.1R(\', \')+\'}\'},70:o(a){D b=[];J(D c 1t a)b.O(c);B b},3t:o(a){D b=[];J(D c 1t a)b.O(a[c]);B b},2m:o(a){B N.M({},a)}});71.U.1J=o(){D a=7,2o=$A(17),47=2o.4F();B o(){B a.2l(47,2o.1u($A(17)))}};71.U.9t=o(b){D c=7,2o=$A(17),b=2o.4F();B o(a){B c.2l(b,[a||1j.9u].1u(2o))}};N.M(3u.U,{9v:o(){B 7.2K(2,16)},5H:o(){B 7+1},4G:o(a){$R(0,7,1c).1e(a);B 7},2K:o(a,b){D c=7.28(b||10);B\'0\'.4G(a-c.I)+c},1Q:o(){B 9w(7)?7.28():\'18\'}});9x.U.1Q=o(){B\'"\'+7.9y()+\'-\'+(7.9z()+1).2K(2)+\'-\'+7.9A().2K(2)+\'T\'+7.9B().2K(2)+\':\'+7.9C().2K(2)+\':\'+7.9D().2K(2)+\'"\'};D 72={73:o(){D a;J(D i=0,I=17.I;i<I;i++){D b=17[i];1P{a=b();1y}1V(e){}}B a}};D 74=1C.1D();74.U={26:o(a,b){7.3v=a;7.3c=b;7.4H=1d;7.3d()},3d:o(){7.3w=75(7.3e.1J(7),7.3c*5I)},5J:o(){C(!7.3w)B;9E(7.3w);7.3w=18},3e:o(){C(!7.4H){1P{7.4H=1c;7.3v(7)}9F{7.4H=1d}}}};N.M(1S,{5K:o(a){B a==18?\'\':1S(a)},76:{\'\\b\':\'\\\\b\',\'\\t\':\'\\\\t\',\'\\n\':\'\\\\n\',\'\\f\':\'\\\\f\',\'\\r\':\'\\\\r\',\'\\\\\':\'\\\\\\\\\'}});N.M(1S.U,{29:o(a,b){D c=\'\',2L=7,1g;b=17.5L.5M(b);1o(2L.I>0){C(1g=2L.1g(a)){c+=2L.3x(0,1g.4I);c+=1S.5K(b(1g));2L=2L.3x(1g.4I+1g[0].I)}1b{c+=2L,2L=\'\'}}B c},77:o(b,c,d){c=7.29.5M(c);d=d===1l?1:d;B 7.29(b,o(a){C(--d<0)B a[0];B c(a)})},78:o(a,b){7.29(a,b);B 7},9G:o(a,b){a=a||30;b=b===1l?\'...\':b;B 7.I>a?7.3x(0,a-b.I)+b:7},3f:o(){B 7.1v(/^\\s+/,\'\').1v(/\\s+$/,\'\')},79:o(){B 7.1v(/<\\/?[^>]+>/5N,\'\')},2p:o(){B 7.1v(V 1W(12.4E,\'7a\'),\'\')},7b:o(){D b=V 1W(12.4E,\'7a\');D c=V 1W(12.4E,\'9H\');B(7.1g(b)||[]).20(o(a){B(a.1g(c)||[\'\',\'\'])[1]})},3y:o(){B 7.7b().20(o(a){B 4J(a)})},4K:o(){D a=17.5L;a.2q.9I=7;B a.2d.2r},7c:o(){D c=11.2y(\'2d\');c.2r=7.79();B c.2a[0]?(c.2a.I>1?$A(c.2a).2A(\'\',o(a,b){B a+b.48}):c.2a[0].48):\'\'},4L:o(e){D f=7.3f().1g(/([^?#]*)(#.*)?$/);C(!f)B{};B f[1].3z(e||\'&\').2A({},o(a,b){C((b=b.3z(\'=\'))[0]){D c=7d(b.4F());D d=b.I>1?b.1R(\'=\'):b[0];C(d!=1l)d=7d(d);C(c 1t a){C(a[c].3g!=1E)a[c]=[a[c]];a[c].O(d)}1b a[c]=d}B a})},2b:o(){B 7.3z(\'\')},5H:o(){B 7.3x(0,7.I-1)+1S.9J(7.7e(7.I-1)+1)},4G:o(a){D b=\'\';J(D i=0;i<a;i++)b+=7;B b},4M:o(){D a=7.3z(\'-\'),5O=a.I;C(5O==1)B a[0];D b=7.4N(0)==\'-\'?a[0].4N(0).1X()+a[0].49(1):a[0];J(D i=1;i<5O;i++)b+=a[i].4N(0).1X()+a[i].49(1);B b},5P:o(){B 7.4N(0).1X()+7.49(1).21()},9K:o(){B 7.29(/::/,\'/\').29(/([A-Z]+)([A-Z][a-z])/,\'#{1}4a#{2}\').29(/([a-z\\d])([A-Z])/,\'#{1}4a#{2}\').29(/-/,\'4a\').21()},9L:o(){B 7.29(/4a/,\'-\')},1H:o(c){D d=7.29(/[\\9M-\\9N\\\\]/,o(a){D b=1S.76[a[0]];B b?b:\'\\\\9O\'+a[0].7e().2K(2,16)});C(c)B\'"\'+d.1v(/"/g,\'\\\\"\')+\'"\';B"\'"+d.1v(/\'/g,\'\\\\\\\'\')+"\'"},1Q:o(){B 7.1H(1c)},5Q:o(a){B 7.77(a||12.6Z,\'#{1}\')},4O:o(a){D b=7.5Q();1P{C(!a||(V 1W(\'^("(\\\\\\\\.|[^"\\\\\\\\\\\\n\\\\r])\'+\'*\'+\'?"|[,:{}\\\\[\\\\]0-9.\\\\-+9P-u \\\\n\\\\r\\\\t])+?$\').2M(b))){B 4J(\'(\'+b+\')\')}}1V(e){}2z V 9Q(\'9R 9S 7f 2B: \'+7.1H());},1p:o(a){B 7.3s(a)>-1},7g:o(a){B 7.3s(a)===0},7h:o(a){D d=7.I-a.I;B d>=0&&7.9T(a)===d},4b:o(){B 7==\'\'},7i:o(){B/^\\s*$/.2M(7)}});C(12.1Z.3r||12.1Z.3X){N.M(1S.U,{4K:o(){B 7.1v(/&/g,\'&7j;\').1v(/</g,\'&7k;\').1v(/>/g,\'&7l;\')},7c:o(){B 7.1v(/&7j;/g,\'&\').1v(/&7k;/g,\'<\').1v(/&7l;/g,\'>\')}})}1S.U.29.5M=o(b){C(1m b==\'o\')B b;D c=V 22(b);B o(a){B c.25(a)}};1S.U.9U=1S.U.4L;N.M(1S.U.4K,{2d:11.2y(\'2d\'),2q:11.9V(\'\')});7m(1S.U.4K)2d.5R(2q);D 22=1C.1D();22.7n=/(^|.|\\r|\\n)(#\\{(.*?)\\})/;22.U={26:o(a,b){7.7o=a.28();7.7p=b||22.7n},25:o(c){B 7.7o.29(7.7p,o(a){D b=a[1];C(b==\'\\\\\')B a[2];B b+1S.5K(c[a[3]])})}};D $1y={};D $2e=V 9W(\'"2z $2e" 9X 9Y, 9Z "B" a0\');D 23={1e:o(b){D c=0;1P{7.2f(o(a){b(a,c++)})}1V(e){C(e!=$1y)2z e;}B 7},7q:o(a,b){D c=-a,5S=[],5T=7.2b();1o((c+=a)<5T.I)5S.O(5T.3x(c,c+a));B 5S.20(b)},a1:o(c){D d=1c;7.1e(o(a,b){d=d&&!!(c||12.K)(a,b);C(!d)2z $1y;});B d},a2:o(c){D d=1d;7.1e(o(a,b){C(d=!!(c||12.K)(a,b))2z $1y;});B d},7r:o(c){D d=[];7.1e(o(a,b){d.O((c||12.K)(a,b))});B d},7s:o(c){D d;7.1e(o(a,b){C(c(a,b)){d=a;2z $1y;}});B d},7t:o(c){D d=[];7.1e(o(a,b){C(c(a,b))d.O(a)});B d},a3:o(d,e){D f=[];7.1e(o(a,b){D c=a.28();C(c.1g(d))f.O((e||12.K)(a,b))});B f},1p:o(b){D c=1d;7.1e(o(a){C(a==b){c=1c;2z $1y;}});B c},a4:o(b,c){c=c===1l?18:c;B 7.7q(b,o(a){1o(a.I<b)a.O(c);B a})},2A:o(c,d){7.1e(o(a,b){c=d(c,a,b)});B c},5U:o(b){D c=$A(17).3x(1);B 7.20(o(a){B a[b].2l(a,c)})},a5:o(c){D d;7.1e(o(a,b){a=(c||12.K)(a,b);C(d==1l||a>=d)d=a});B d},a6:o(c){D d;7.1e(o(a,b){a=(c||12.K)(a,b);C(d==1l||a<d)d=a});B d},a7:o(c){D d=[],5V=[];7.1e(o(a,b){((c||12.K)(a,b)?d:5V).O(a)});B[d,5V]},4c:o(c){D d=[];7.1e(o(a,b){d.O(a[c])});B d},a8:o(c){D d=[];7.1e(o(a,b){C(!c(a,b))d.O(a)});B d},a9:o(e){B 7.20(o(a,b){B{1w:a,4d:e(a,b)}}).aa(o(c,d){D a=c.4d,b=d.4d;B a<b?-1:a>b?1:0}).4c(\'1w\')},2b:o(){B 7.20()},ab:o(){D c=12.K,2o=$A(17);C(1m 2o.1z()==\'o\')c=2o.ac();D d=[7].1u(2o).20($A);B 7.20(o(a,b){B c(d.4c(b))})},7u:o(){B 7.2b().I},1H:o(){B\'#<23:\'+7.2b().1H()+\'>\'}};N.M(23,{20:23.7r,7v:23.7s,2g:23.7t,ad:23.1p,ae:23.2b});D $A=1E.7w=o(a){C(!a)B[];C(a.2b){B a.2b()}1b{D b=[];J(D i=0,I=a.I;i<I;i++)b.O(a[i]);B b}};C(12.1Z.3r){$A=1E.7w=o(a){C(!a)B[];C(!(1m a==\'o\'&&a==\'[47 af]\')&&a.2b){B a.2b()}1b{D b=[];J(D i=0,I=a.I;i<I;i++)b.O(a[i]);B b}}}N.M(1E.U,23);C(!1E.U.5W)1E.U.5W=1E.U.4P;N.M(1E.U,{2f:o(a){J(D i=0,I=7.I;i<I;i++)a(7[i])},7x:o(){7.I=0;B 7},2h:o(){B 7[0]},1z:o(){B 7[7.I-1]},ag:o(){B 7.2g(o(a){B a!=18})},7y:o(){B 7.2A([],o(a,b){B a.1u(b&&b.3g==1E?b.7y():[b])})},5X:o(){D b=$A(17);B 7.2g(o(a){B!b.1p(a)})},3s:o(a){J(D i=0,I=7.I;i<I;i++)C(7[i]==a)B i;B-1},4P:o(a){B(a!==1d?7:7.2b()).5W()},ah:o(){B 7.I>1?7:7[0]},ai:o(d){B 7.2A([],o(a,b,c){C(0==c||(d?a.1z()!=b:!a.1p(b)))a.O(b);B a})},2m:o(){B[].1u(7)},7u:o(){B 7.I},1H:o(){B\'[\'+7.20(N.1H).1R(\', \')+\']\'},1Q:o(){D c=[];7.1e(o(a){D b=N.1Q(a);C(b!==1l)c.O(b)});B\'[\'+c.1R(\', \')+\']\'}});1E.U.2b=1E.U.2m;o $w(a){a=a.3f();B a?a.3z(/\\s+/):[]}C(12.1Z.5A){1E.U.1u=o(){D a=[];J(D i=0,I=7.I;i<I;i++)a.O(7[i]);J(D i=0,I=17.I;i<I;i++){C(17[i].3g==1E){J(D j=0,7z=17[i].I;j<7z;j++)a.O(17[i][j])}1b{a.O(17[i])}}B a}}D 1F=o(a){C(a 5F 1F)7.7A(a);1b N.M(7,a||{})};N.M(1F,{3h:o(d){D e=[];e.3A=17.5L.7B;7.U.2f.5Y(d,o(b){C(!b.2i)B;D c=b.1w;C(c&&1m c==\'47\'){C(c.3g==1E)c.1e(o(a){e.3A(b.2i,a)});B}e.3A(b.2i,c)});B e.1R(\'&\')},1Q:o(c){D d=[];7.U.2f.5Y(c,o(a){D b=N.1Q(a.1w);C(b!==1l)d.O(a.2i.1Q()+\': \'+b)});B\'{\'+d.1R(\', \')+\'}\'}});1F.3h.7B=o(a,b,c){a=7C(a);C(b===1l)7.O(a);1b 7.O(a+\'=\'+(b==18?\'\':7C(b)))};N.M(1F.U,23);N.M(1F.U,{2f:o(a){J(D b 1t 7){D c=7[b];C(c&&c==1F.U[b])2e;D d=[b,c];d.2i=b;d.1w=c;a(d)}},70:o(){B 7.4c(\'2i\')},3t:o(){B 7.4c(\'1w\')},7A:o(c){B $H(c).2A(7,o(a,b){a[b.2i]=b.1w;B a})},4e:o(){D a;J(D i=0,I=17.I;i<I;i++){D b=7[17[i]];C(b!==1l){C(a===1l)a=b;1b{C(a.3g!=1E)a=[a];a.O(b)}}7D 7[17[i]]}B a},3h:o(){B 1F.3h(7)},1H:o(){B\'#<1F:{\'+7.20(o(a){B a.20(N.1H).1R(\': \')}).1R(\', \')+\'}>\'},1Q:o(){B 1F.1Q(7)}});o $H(a){C(a 5F 1F)B a;B V 1F(a)};C(o(){D i=0,5Z=o(a){7.2i=a};5Z.U.2i=\'aj\';J(D b 1t V 5Z(\'ak\'))i++;B i>1}())1F.U.2f=o(a){D b=[];J(D c 1t 7){D d=7[c];C((d&&d==1F.U[c])||b.1p(c))2e;b.O(c);D e=[c,d];e.2i=c;e.1w=d;a(e)}};4Q=1C.1D();N.M(4Q.U,23);N.M(4Q.U,{26:o(a,b,c){7.4f=a;7.60=b;7.7E=c},2f:o(a){D b=7.4f;1o(7.1p(b)){a(b);b=b.5H()}},1p:o(a){C(a<7.4f)B 1d;C(7.7E)B a<7.60;B a<=7.60}});D $R=o(a,b,c){B V 4Q(a,b,c)};D 1h={61:o(){B 72.73(o(){B V 7F()},o(){B V 7G(\'al.7H\')},o(){B V 7G(\'am.7H\')})||1d},62:0};1h.3B={4g:[],2f:o(a){7.4g.2f(a)},7I:o(a){C(!7.1p(a))7.4g.O(a)},an:o(a){7.4g=7.4g.5X(a)},4R:o(b,c,d,f){7.1e(o(a){C(1m a[b]==\'o\'){1P{a[b].2l(a,[c,d,f])}1V(e){}}})}};N.M(1h.3B,23);1h.3B.7I({4S:o(){1h.62++},2s:o(){1h.62--}});1h.4T=o(){};1h.4T.U={4U:o(a){7.14={1K:\'4h\',4V:1c,7J:\'63/x-ao-5D-ap\',64:\'aq-8\',2C:\'\'};N.M(7.14,a||{});7.14.1K=7.14.1K.21();C(1m 7.14.2C==\'2B\')7.14.2C=7.14.2C.4L()}};1h.3C=1C.1D();1h.3C.7K=[\'ar\',\'as\',\'at\',\'au\',\'65\'];1h.3C.U=N.M(V 1h.4T(),{66:1d,26:o(a,b){7.1q=1h.61();7.4U(b);7.4W(a)},4W:o(a){7.3D=a;7.1K=7.14.1K;D b=N.2m(7.14.2C);C(![\'7L\',\'4h\'].1p(7.1K)){b[\'av\']=7.1K;7.1K=\'4h\'}7.2C=b;C(b=1F.3h(b)){C(7.1K==\'7L\')7.3D+=(7.3D.1p(\'?\')?\'&\':\'?\')+b;1b C(/aw|ax|6Y/.2M(3Z.41))b+=\'&4a=\'}1P{C(7.14.4S)7.14.4S(7.1q);1h.3B.4R(\'4S\',7,7.1q);7.1q.ay(7.1K.1X(),7.3D,7.14.4V);C(7.14.4V)3i(o(){7.67(1)}.1J(7),10);7.1q.7M=7.68.1J(7);7.7N();7.1T=7.1K==\'4h\'?(7.14.az||b):18;7.1q.aA(7.1T);C(!7.14.4V&&7.1q.7O)7.68()}1V(e){7.4i(e)}},68:o(){D a=7.1q.7P;C(a>1&&!((a==4)&&7.66))7.67(7.1q.7P)},7N:o(){D b={\'X-aB-aC\':\'7F\',\'X-12-5z\':12.5z,\'aD\':\'2q/aE, 2q/aF, 63/7Q, 2q/7Q, */*\'};C(7.1K==\'4h\'){b[\'7R-1f\']=7.14.7J+(7.14.64?\'; aG=\'+7.14.64:\'\');C(7.1q.7O&&(3Z.41.1g(/4D\\/(\\d{4})/)||[0,7S])[1]<7S)b[\'aH\']=\'aI\'}C(1m 7.14.7T==\'47\'){D c=7.14.7T;C(1m c.O==\'o\')J(D i=0,I=c.I;i<I;i+=2)b[c[i]]=c[i+1];1b $H(c).1e(o(a){b[a.2i]=a.1w})}J(D d 1t b)7.1q.aJ(d,b[d])},2N:o(){B!7.1q.4X||(7.1q.4X>=aK&&7.1q.4X<aL)},67:o(a){D b=1h.3C.7K[a];D c=7.1q,4Y=7.4O();C(b==\'65\'){1P{7.66=1c;(7.14[\'3E\'+7.1q.4X]||7.14[\'3E\'+(7.2N()?\'aM\':\'aN\')]||12.2J)(c,4Y)}1V(e){7.4i(e)}D d=7.69(\'7R-1f\');C(d&&d.3f().1g(/^(2q|63)\\/(x-)?(aO|aP)5E(;.*)?$/i))7.7U()}1P{(7.14[\'3E\'+b]||12.2J)(c,4Y);1h.3B.4R(\'3E\'+b,7,c,4Y)}1V(e){7.4i(e)}C(b==\'65\'){7.1q.7M=12.2J}},69:o(a){1P{B 7.1q.aQ(a)}1V(e){B 18}},4O:o(){1P{D a=7.69(\'X-7f\');B a?a.4O():18}1V(e){B 18}},7U:o(){1P{B 4J((7.1q.4Z||\'\').5Q())}1V(e){7.4i(e)}},4i:o(a){(7.14.7V||12.2J)(7,a);1h.3B.4R(\'7V\',7,a)}});1h.6a=1C.1D();N.M(N.M(1h.6a.U,1h.3C.U),{26:o(c,d,e){7.50={2N:(c.2N||c),6b:(c.6b||(c.2N?18:c))};7.1q=1h.61();7.4U(e);D f=7.14.2s||12.2J;7.14.2s=(o(a,b){7.7W();f(a,b)}).1J(7);7.4W(d)},7W:o(){D a=7.50[7.2N()?\'2N\':\'6b\'];D b=7.1q.4Z;C(!7.14.3y)b=b.2p();C(a=$(a)){C(7.14.7X)V 7.14.7X(a,b);1b a.6c(b)}C(7.2N()){C(7.2s)3i(7.2s.1J(7),10)}}});1h.7Y=1C.1D();1h.7Y.U=N.M(V 1h.4T(),{26:o(a,b,c){7.4U(c);7.2s=7.14.2s;7.3c=(7.14.3c||2);7.3j=(7.14.3j||1);7.6d={};7.50=a;7.3D=b;7.4f()},4f:o(){7.14.2s=7.7Z.1J(7);7.3e()},5J:o(){7.6d.14.2s=1l;aR(7.3w);(7.2s||12.2J).2l(7,17)},7Z:o(a){C(7.14.3j){7.3j=(a.4Z==7.80?7.3j*7.14.3j:1);7.80=a.4Z}7.3w=3i(7.3e.1J(7),7.3j*7.3c*5I)},3e:o(){7.6d=V 1h.6a(7.50,7.3D,7.14)}});o $(a){C(17.I>1){J(D i=0,6e=[],I=17.I;i<I;i++)6e.O($(17[i]));B 6e}C(1m a==\'2B\')a=11.aS(a);B G.M(a)}C(12.3b.5B){11.6f=o(a,b){D c=[];D d=11.25(a,$(b)||11,18,aT.aU,18);J(D i=0,I=d.aV;i<I;i++)c.O(d.aW(i));B c};11.51=o(a,b){D q=".//*[4j(1u(\' \', @6g, \' \'), \' "+a+" \')]";B 11.6f(q,b)}}1b{11.51=o(a,b){D c=($(b)||11.1T).2D(\'*\');D d=[],1i;J(D i=0,I=c.I;i<I;i++){1i=c[i];C(G.6h(1i,a))d.O(G.M(1i))}B d}}C(!1j.G)D G={};G.M=o(a){D F=12.3b;C(!a||!a.1k||a.2t==3||a.81||F.5C||a==1j)B a;D b={},1k=a.1k,4k=G.M.4k,T=G.19.2E;C(!F.42){N.M(b,G.19),N.M(b,G.19.52)}C(T[1k])N.M(b,T[1k]);J(D c 1t b){D d=b[c];C(1m d==\'o\'&&!(c 1t a))a[c]=4k.6i(d)}a.81=12.2J;B a};G.M.4k={6i:o(a){B 7[a]=7[a]||o(){B a.2l(18,[7].1u($A(17)))}}};G.19={6j:o(a){B $(a).Y.2F!=\'53\'},82:o(a){a=$(a);G[G.6j(a)?\'83\':\'84\'](a);B a},83:o(a){$(a).Y.2F=\'53\';B a},84:o(a){$(a).Y.2F=\'\';B a},4e:o(a){a=$(a);a.1L.6k(a);B a},6c:o(a,b){b=1m b==\'1l\'?\'\':b.28();$(a).2r=b.2p();3i(o(){b.3y()},10);B a},1v:o(a,b){a=$(a);b=1m b==\'1l\'?\'\':b.28();C(a.85){a.85=b.2p()}1b{D c=a.5G.86();c.6l(a);a.1L.aX(c.87(b.2p()),a)}3i(o(){b.3y()},10);B a},1H:o(d){d=$(d);D e=\'<\'+d.1k.21();$H({\'2O\':\'2O\',\'2u\':\'6g\'}).1e(o(a){D b=a.2h(),88=a.1z();D c=(d[b]||\'\').28();C(c)e+=\' \'+88+\'=\'+c.1H(1c)});B e+\'>\'},54:o(a,b){a=$(a);D c=[];1o(a=a[b])C(a.2t==1)c.O(G.M(a));B c},89:o(a){B $(a).54(\'1L\')},8a:o(a){B $A($(a).2D(\'*\')).1e(G.M)},8b:o(a){a=$(a).3F;1o(a&&a.2t!=1)a=a.3G;B $(a)},8c:o(a){C(!(a=$(a).3F))B[];1o(a&&a.2t!=1)a=a.3G;C(a)B[a].1u($(a).4l());B[]},6m:o(a){B $(a).54(\'8d\')},4l:o(a){B $(a).54(\'3G\')},aY:o(a){a=$(a);B a.6m().4P().1u(a.4l())},1g:o(a,b){C(1m b==\'2B\')b=V L(b);B b.1g($(a))},aZ:o(a,b,c){a=$(a);C(17.I==1)B $(a.1L);D d=a.89();B b?L.3H(d,b,c):d[c||0]},b0:o(a,b,c){a=$(a);C(17.I==1)B a.8b();D d=a.8a();B b?L.3H(d,b,c):d[c||0]},b1:o(a,b,c){a=$(a);C(17.I==1)B $(L.1r.4m(a));D d=a.6m();B b?L.3H(d,b,c):d[c||0]},b2:o(a,b,c){a=$(a);C(17.I==1)B $(L.1r.4n(a));D d=a.4l();B b?L.3H(d,b,c):d[c||0]},b3:o(){D a=$A(17),15=$(a.4F());B L.6n(15,a)},51:o(a,b){B 11.51(b,a)},6o:o(a,b){a=$(a);C(12.1Z.3X){C(!a.8e)B 18;D t=G.55;C(t.3t[b])B t.3t[b](a,b);C(t.56[b])b=t.56[b];D c=a.8e[b];B c?c.48:18}B a.8f(b)},b4:o(a){B $(a).6p().2P},b5:o(a){B $(a).6p().2Q},57:o(a){B V G.58(a)},6h:o(a,b){C(!(a=$(a)))B;D c=a.2u;C(c.I==0)B 1d;C(c==b||c.1g(V 1W("(^|\\\\s)"+b+"(\\\\s|$)")))B 1c;B 1d},b6:o(a,b){C(!(a=$(a)))B;G.57(a).3A(b);B a},b7:o(a,b){C(!(a=$(a)))B;G.57(a).4e(b);B a},b8:o(a,b){C(!(a=$(a)))B;G.57(a)[a.6h(b)?\'4e\':\'3A\'](b);B a},3I:o(){1x.3I.2l(1x,17);B $A(17).2h()},59:o(){1x.59.2l(1x,17);B $A(17).2h()},b9:o(a){a=$(a);D b=a.3F;1o(b){D c=b.3G;C(b.2t==3&&!/\\S/.2M(b.48))a.6k(b);b=c}B a},4b:o(a){B $(a).2r.7i()},5a:o(a,b){a=$(a),b=$(b);1o(a=a.1L)C(a==b)B 1c;B 1d},8g:o(a){a=$(a);D b=2G.4o(a);1j.8g(b[0],b[1]);B a},1M:o(a,b){a=$(a);b=b==\'6q\'?\'5b\':b.4M();D c=a.Y[b];C(!c){D d=11.ba.bb(a,18);c=d?d[b]:18}C(b==\'2R\')B c?3J(c):1.0;B c==\'5c\'?18:c},bc:o(a){B $(a).1M(\'2R\')},bd:o(a,b,c){a=$(a);D d=a.Y;J(D e 1t b)C(e==\'2R\')a.5d(b[e]);1b d[(e==\'6q\'||e==\'5b\')?(d.6r===1l?\'5b\':\'6r\'):(c?e:e.4M())]=b[e];B a},5d:o(a,b){a=$(a);a.Y.2R=(b==1||b===\'\')?\'\':(b<0.6s)?0:b;B a},6p:o(a){a=$(a);D b=$(a).1M(\'2F\');C(b!=\'53\'&&b!=18)B{2Q:a.3K,2P:a.3L};D c=a.Y;D d=c.6t;D e=c.1A;D f=c.2F;c.6t=\'5e\';c.1A=\'3k\';c.2F=\'be\';D g=a.8h;D h=a.8i;c.2F=f;c.1A=e;c.6t=d;B{2Q:g,2P:h}},bf:o(a){a=$(a);D b=G.1M(a,\'1A\');C(b==\'6u\'||!b){a.6v=1c;a.Y.1A=\'5f\';C(1j.4C){a.Y.2S=0;a.Y.2T=0}}B a},bg:o(a){a=$(a);C(a.6v){a.6v=1l;a.Y.1A=a.Y.2S=a.Y.2T=a.Y.8j=a.Y.8k=\'\'}B a},bh:o(a){a=$(a);C(a.3M)B a;a.3M=a.Y.5g||\'5c\';C((G.1M(a,\'5g\')||\'6j\')!=\'5e\')a.Y.5g=\'5e\';B a},bi:o(a){a=$(a);C(!a.3M)B a;a.Y.5g=a.3M==\'5c\'?\'\':a.3M;a.3M=18;B a}};N.M(G.19,{bj:G.19.5a,bk:G.19.8c});C(12.1Z.5A){G.19.6w=G.19.1M;G.19.1M=o(a,b){45(b){1I\'2T\':1I\'2S\':1I\'8k\':1I\'8j\':C(G.6w(a,\'1A\')==\'6u\')B 18;6x:B G.6w(a,b)}}}1b C(12.1Z.3X){G.19.1M=o(a,b){a=$(a);b=(b==\'6q\'||b==\'5b\')?\'6r\':b.4M();D c=a.Y[b];C(!c&&a.8l)c=a.8l[b];C(b==\'2R\'){C(c=(a.1M(\'5h\')||\'\').1g(/5i\\(2R=(.*)\\)/))C(c[1])B 3J(c[1])/8m;B 1.0}C(c==\'5c\'){C((b==\'2Q\'||b==\'2P\')&&(a.1M(\'2F\')!=\'53\'))B a[\'24\'+b.5P()]+\'2j\';B 18}B c};G.19.5d=o(a,b){a=$(a);D c=a.1M(\'5h\'),Y=a.Y;C(b==1||b===\'\'){Y.5h=c.1v(/5i\\([^\\)]*\\)/5N,\'\');B a}1b C(b<0.6s)b=0;Y.5h=c.1v(/5i\\([^\\)]*\\)/5N,\'\')+\'5i(2R=\'+(b*8m)+\')\';B a};G.19.6c=o(b,c){b=$(b);c=1m c==\'1l\'?\'\':c.28();D d=b.1k.1X();C([\'6y\',\'5j\',\'5k\',\'6z\'].1p(d)){D e=11.2y(\'2d\');45(d){1I\'6y\':1I\'5j\':e.2r=\'<2U><2V>\'+c.2p()+\'</2V></2U>\';5l=2;1y;1I\'5k\':e.2r=\'<2U><2V><5m>\'+c.2p()+\'</5m></2V></2U>\';5l=3;1y;1I\'6z\':e.2r=\'<2U><2V><5m><8n>\'+c.2p()+\'</8n></5m></2V></2U>\';5l=4}$A(b.2a).1e(o(a){b.6k(a)});5l.4G(o(){e=e.3F});$A(e.2a).1e(o(a){b.5R(a)})}1b{b.2r=c.2p()}3i(o(){c.3y()},10);B b}}1b C(12.1Z.4D){G.19.5d=o(a,b){a=$(a);a.Y.2R=(b==1)?0.bl:(b===\'\')?\'\':(b<0.6s)?0:b;B a}}G.55={56:{bm:"bn",bo:"bp",bq:"br",bs:"bt",bu:"bv",bw:"bx",by:"bz",bA:"bB",8o:"bC",bD:"bE"},3t:{5n:o(a,b){B a.8f(b,2)},4p:o(a,b){B $(a).2H(b)?b:18},Y:o(a){B a.Y.bF.21()},8p:o(a){D b=a.8q(\'8p\');B b.8r?b.48:18}}};(o(){N.M(7,{bG:7.5n,bH:7.5n,1f:7.5n,2c:7.4p,3l:7.4p,8o:7.4p,bI:7.4p})}).5Y(G.55.3t);G.19.52={2H:o(a,b){D t=G.55,E;b=t.56[b]||b;E=$(a).8q(b);B E&&E.8r}};G.19.2E={};N.M(G,G.19);C(!12.3b.42&&11.2y(\'2d\').44){1j.43={};1j.43.U=11.2y(\'2d\').44;12.3b.42=1c}G.2H=o(a,b){C(a.2H)B a.2H(b);B G.19.52.2H(a,b)};G.8s=o(g){D F=12.3b,T=G.19.2E;C(!g){N.M(1a,1a.19);N.M(1a.G,1a.G.19);N.M(G.19.2E,{"bJ":N.2m(1a.19),"bK":N.2m(1a.G.19),"bL":N.2m(1a.G.19),"8t":N.2m(1a.G.19)})}C(17.I==2){D h=g;g=17[1]}C(!h)N.M(G.19,g||{});1b{C(h.3g==1E)h.1e(M);1b M(h)}o M(a){a=a.1X();C(!G.19.2E[a])G.19.2E[a]={};N.M(G.19.2E[a],g)}o 5o(a,b,c){c=c||1d;D d=G.M.4k;J(D e 1t a){D f=a[e];C(!c||!(e 1t b))b[e]=d.6i(f)}}o 8u(a){D b;D c={"bM":"bN","8t":"bO","P":"bP","bQ":"bR","bS":"bT","bU":"bV","bW":"bX","bY":"bZ","c0":"3N","c1":"3N","c2":"3N","c3":"3N","c4":"3N","c5":"3N","Q":"c6","c7":"8v","c8":"8v","A":"c9","ca":"cb","cc":"cd","ce":"8w","cf":"8w","6y":"6A","cg":"6A","5j":"6A","5k":"ch","ci":"8x","6z":"8x","cj":"ck","cl":"cm"};C(c[a])b=\'6B\'+c[a]+\'G\';C(1j[b])B 1j[b];b=\'6B\'+a+\'G\';C(1j[b])B 1j[b];b=\'6B\'+a.5P()+\'G\';C(1j[b])B 1j[b];1j[b]={};1j[b].U=11.2y(a).44;B 1j[b]}C(F.42){5o(G.19,43.U);5o(G.19.52,43.U,1c)}C(F.5C){J(D i 1t G.19.2E){D j=8u(i);C(1m j=="1l")2e;5o(T[i],j.U)}}N.M(G,G.19);7D G.2E};D cn={2F:G.82};1O.1U=o(a){7.6C=a};1O.1U.U={26:o(a,b){7.15=$(a);7.5p=b.2p();C(7.6C&&7.15.8y){1P{7.15.8y(7.6C,7.5p)}1V(e){D c=7.15.1k.1X();C([\'5j\',\'5k\'].1p(c)){7.3O(7.8z())}1b{2z e;}}}1b{7.2W=7.15.5G.86();C(7.3P)7.3P();7.3O([7.2W.87(7.5p)])}3i(o(){b.3y()},10)},8z:o(){D a=11.2y(\'2d\');a.2r=\'<2U><2V>\'+7.5p+\'</2V></2U>\';B $A(a.2a[0].2a[0].2a)}};D 1U=V N();1U.8A=1C.1D();1U.8A.U=N.M(V 1O.1U(\'co\'),{3P:o(){7.2W.cp(7.15)},3O:o(b){b.1e((o(a){7.15.1L.6D(a,7.15)}).1J(7))}});1U.8B=1C.1D();1U.8B.U=N.M(V 1O.1U(\'cq\'),{3P:o(){7.2W.6l(7.15);7.2W.8C(1c)},3O:o(b){b.4P(1d).1e((o(a){7.15.6D(a,7.15.3F)}).1J(7))}});1U.8D=1C.1D();1U.8D.U=N.M(V 1O.1U(\'cr\'),{3P:o(){7.2W.6l(7.15);7.2W.8C(7.15)},3O:o(b){b.1e((o(a){7.15.5R(a)}).1J(7))}});1U.8E=1C.1D();1U.8E.U=N.M(V 1O.1U(\'cs\'),{3P:o(){7.2W.ct(7.15)},3O:o(b){b.1e((o(a){7.15.1L.6D(a,7.15.3G)}).1J(7))}});G.58=1C.1D();G.58.U={26:o(a){7.15=$(a)},2f:o(b){7.15.2u.3z(/\\s+/).2g(o(a){B a.I>0}).2f(b)},6E:o(a){7.15.2u=a},3A:o(a){C(7.1p(a))B;7.6E($A(7).1u(a).1R(\' \'))},4e:o(a){C(!7.1p(a))B;7.6E($A(7).5X(a).1R(\' \'))},28:o(){B $A(7).1R(\' \')}};N.M(G.58.U,23);D L=1C.1D();L.U={26:o(a){7.2X=a.3f();7.8F()},8F:o(){C(12.3b.5B&&!(/\\[[\\w-]*?:/).2M(7.2X))B 7.8G();D e=7.2X,3Q=L.5q,h=L.1r,c=L.4d,2I,p,m;C(L.3m[e]){7.2k=L.3m[e];B}7.2k=["7.2k = o(8H) {","D r = 8H, h = L.1r, c = 1d, n;"];1o(e&&2I!=e&&(/\\S/).2M(e)){2I=e;J(D i 1t 3Q){p=3Q[i];C(m=e.1g(p)){7.2k.O(1m c[i]==\'o\'?c[i](m):V 22(c[i]).25(m));e=e.1v(m[0],\'\');1y}}}7.2k.O("B h.6F(n);\\n}");4J(7.2k.1R(\'\\n\'));L.3m[7.2X]=7.2k},8G:o(){D e=7.2X,3Q=L.5q,x=L.1B,2I,m;C(L.3m[e]){7.1B=L.3m[e];B}7.2k=[\'.//*\'];1o(e&&2I!=e&&(/\\S/).2M(e)){2I=e;J(D i 1t 3Q){C(m=e.1g(3Q[i])){7.2k.O(1m x[i]==\'o\'?x[i](m):V 22(x[i]).25(m));e=e.1v(m[0],\'\');1y}}}7.1B=7.2k.1R(\'\');L.3m[7.2X]=7.1B},4q:o(a){a=a||11;C(7.1B)B 11.6f(7.1B,a);B 7.2k(a)},1g:o(a){B 7.4q(11).1p(a)},28:o(){B 7.2X},1H:o(){B"#<L:"+7.2X.1H()+">"}};N.M(L,{3m:{},1B:{2Y:"//*",1i:"/*",3R:"/4r-2Z::*[1]",4s:\'/4r-2Z::*\',1k:o(m){C(m[1]==\'*\')B\'\';B"[8I-3n()=\'"+m[1].21()+"\' 6G 8I-3n()=\'"+m[1].1X()+"\']"},2u:"[4j(1u(\' \', @6g, \' \'), \' #{1} \')]",2O:"[@2O=\'#{1}\']",4t:"[@#{1}]",4u:o(m){m[3]=m[5]||m[6];B V 22(L.1B.5r[m[2]]).25(m)},4v:o(m){D h=L.1B.1s[m[1]];C(!h)B\'\';C(1m h===\'o\')B h(m);B V 22(L.1B.1s[m[1]]).25(m)},5r:{\'=\':"[@#{1}=\'#{3}\']",\'!=\':"[@#{1}!=\'#{3}\']",\'^=\':"[cu-7m(@#{1}, \'#{3}\')]",\'$=\':"[49(@#{1}, (2B-I(@#{1}) - 2B-I(\'#{3}\') + 1))=\'#{3}\']",\'*=\':"[4j(@#{1}, \'#{3}\')]",\'~=\':"[4j(1u(\' \', @#{1}, \' \'), \' #{3} \')]",\'|=\':"[4j(1u(\'-\', @#{1}, \'-\'), \'-#{3}-\')]"},1s:{\'2h-1i\':\'[31(6H-2Z::*)]\',\'1z-1i\':\'[31(4r-2Z::*)]\',\'4w-1i\':\'[31(6H-2Z::* 6G 4r-2Z::*)]\',\'4b\':"[5s(*) = 0 6I (5s(2q()) = 0 6G cv(2q(), \' \\t\\r\\n\', \'\') = \'\')]",\'3l\':"[@3l]",\'2c\':"[@2c]",\'8J\':"[31(@2c)]",\'31\':o(m){D e=m[6],p=L.5q,x=L.1B,2I,m,v;D a=[];1o(e&&2I!=e&&(/\\S/).2M(e)){2I=e;J(D i 1t p){C(m=e.1g(p[i])){v=1m x[i]==\'o\'?x[i](m):V 22(x[i]).25(m);a.O("("+v.49(1,v.I-1)+")");e=e.1v(m[0],\'\');1y}}}B"[31("+a.1R(" 6I ")+")]"},\'1n-1i\':o(m){B L.1B.1s.1n("(5s(./6H-2Z::*) + 1) ",m)},\'1n-1z-1i\':o(m){B L.1B.1s.1n("(5s(./4r-2Z::*) + 1) ",m)},\'1n-1G-1f\':o(m){B L.1B.1s.1n("1A() ",m)},\'1n-1z-1G-1f\':o(m){B L.1B.1s.1n("(1z() + 1 - 1A()) ",m)},\'2h-1G-1f\':o(m){m[6]="1";B L.1B.1s[\'1n-1G-1f\'](m)},\'1z-1G-1f\':o(m){m[6]="1";B L.1B.1s[\'1n-1z-1G-1f\'](m)},\'4w-1G-1f\':o(m){D p=L.1B.1s;B p[\'2h-1G-1f\'](m)+p[\'1z-1G-1f\'](m)},1n:o(c,m){D d,3o=m[6],6J;C(3o==\'8K\')3o=\'2n+0\';C(3o==\'8L\')3o=\'2n+1\';C(d=3o.1g(/^(\\d+)$/))B\'[\'+c+"= "+d[1]+\']\';C(d=3o.1g(/^(-?\\d*)?n(([+-])(\\d+))?/)){C(d[1]=="-")d[1]=-1;D a=d[1]?3u(d[1]):1;D b=d[2]?3u(d[2]):0;6J="[((#{6K} - #{b}) cw #{a} = 0) 6I "+"((#{6K} - #{b}) 2d #{a} >= 0)]";B V 22(6J).25({6K:c,a:a,b:b})}}}},4d:{1k:\'n = h.1k(n, r, "#{1}", c);   c = 1d;\',2u:\'n = h.2u(n, r, "#{1}", c); c = 1d;\',2O:\'n = h.2O(n, r, "#{1}", c);        c = 1d;\',4t:\'n = h.4t(n, r, "#{1}"); c = 1d;\',4u:o(m){m[3]=(m[5]||m[6]);B V 22(\'n = h.4u(n, r, "#{1}", "#{3}", "#{2}"); c = 1d;\').25(m)},4v:o(m){C(m[6])m[6]=m[6].1v(/"/g,\'\\\\"\');B V 22(\'n = h.4v(n, "#{1}", "#{6}", r, c); c = 1d;\').25(m)},2Y:\'c = "2Y";\',1i:\'c = "1i";\',3R:\'c = "3R";\',4s:\'c = "4s";\'},5q:{4s:V 1W(\'^\\\\s\'+\'*\'+\'~\\\\s*\'),1i:V 1W(\'^\\\\s\'+\'*\'+\'>\\\\s*\'),3R:V 1W(\'^\\\\s\'+\'*\'+\'\\\\+\\\\s*\'),2Y:/^\\s/,1k:V 1W(\'^\\\\s*\'+\'(\\\\\'+\'*|[\\\\w\\\\-]+)(\\\\b|$)?\'),2O:V 1W(\'^#([\\\\w\\\\-\\\\\'+\'*]+)(\\\\b|$)\'),2u:V 1W(\'^\\\\.([\\\\w\\\\-\\\\\'+\'*]+)(\\\\b|$)\'),4v:V 1W(\'^:((2h|1z|1n|1n-1z|4w)(-1i|-1G-1f)|4b|3l|(cx|cy)cz|31)(\\\\((.*?)\\\\))?(\\\\b|$|\\\\s||(?=:))\'),4t:V 1W(\'^\\\\[([\\\\w]+)\\\\]\'),4u:V 1W(\'\\\\[((?:[\\\\w-]*:)?[\\\\w-]+)\\\\s*(?:([!^$*~|]?=)\\\\s*(([\\\'"])([^\\\\]]*?)\\\\4|([^\\\'"][^\\\\]]*?)))?\\\\]\')},1r:{1u:o(a,b){J(D i=0,E;E=b[i];i++)a.O(E);B a},5t:o(a){J(D i=0,E;E=a[i];i++)E.2v=1c;B a},3S:o(a){J(D i=0,E;E=a[i];i++)E.2v=1l;B a},4I:o(a,b,c){a.2v=1c;C(b){J(D d=a.2a,i=d.I-1,j=1;i>=0;i--){E=d[i];C(E.2t==1&&(!c||E.2v))E.5u=j++}}1b{J(D i=0,j=1,d=a.2a;E=d[i];i++)C(E.2t==1&&(!c||E.2v))E.5u=j++}},6F:o(a){C(a.I==0)B a;D b=[],n;J(D i=0,l=a.I;i<l;i++)C(!(n=a[i]).2v){n.2v=1c;b.O(G.M(n))}B L.1r.3S(b)},2Y:o(a){D h=L.1r;J(D i=0,W=[],E;E=a[i];i++)h.1u(W,E.2D(\'*\'));B W},1i:o(a){D h=L.1r;J(D i=0,W=[],E;E=a[i];i++){J(D j=0,cA=[],1i;1i=E.2a[j];j++)C(1i.2t==1&&1i.1k!=\'!\')W.O(1i)}B W},3R:o(a){J(D i=0,W=[],E;E=a[i];i++){D b=7.4n(E);C(b)W.O(b)}B W},4s:o(a){D h=L.1r;J(D i=0,W=[],E;E=a[i];i++)h.1u(W,G.4l(E));B W},4n:o(a){1o(a=a.3G)C(a.2t==1)B a;B 18},4m:o(a){1o(a=a.8d)C(a.2t==1)B a;B 18},1k:o(a,b,c,d){c=c.1X();D e=[],h=L.1r;C(a){C(d){C(d=="2Y"){J(D i=0,E;E=a[i];i++)h.1u(e,E.2D(c));B e}1b a=7[d](a);C(c=="*")B a}J(D i=0,E;E=a[i];i++)C(E.1k.1X()==c)e.O(E);B e}1b B b.2D(c)},2O:o(a,b,c,d){D e=$(c),h=L.1r;C(!a&&b==11)B e?[e]:[];C(a){C(d){C(d==\'1i\'){J(D i=0,E;E=a[i];i++)C(e.1L==E)B[e]}1b C(d==\'2Y\'){J(D i=0,E;E=a[i];i++)C(G.5a(e,E))B[e]}1b C(d==\'3R\'){J(D i=0,E;E=a[i];i++)C(L.1r.4m(e)==E)B[e]}1b a=h[d](a)}J(D i=0,E;E=a[i];i++)C(E==e)B[e];B[]}B(e&&G.5a(e,b))?[e]:[]},2u:o(a,b,c,d){C(a&&d)a=7[d](a);B L.1r.8M(a,b,c)},8M:o(a,b,c){C(!a)a=L.1r.2Y([b]);D d=\' \'+c+\' \';J(D i=0,W=[],E,4x;E=a[i];i++){4x=E.2u;C(4x.I==0)2e;C(4x==c||(\' \'+4x+\' \').1p(d))W.O(E)}B W},4t:o(a,b,c){D d=[];J(D i=0,E;E=a[i];i++)C(G.2H(E,c))d.O(E);B d},4u:o(a,b,c,d,e){C(!a)a=b.2D("*");D f=L.5r[e],W=[];J(D i=0,E;E=a[i];i++){D g=G.6o(E,c);C(g===18)2e;C(f(g,d))W.O(E)}B W},4v:o(a,b,c,d,e){C(a&&e)a=7[e](a);C(!a)a=d.2D("*");B L.1s[b](a,c,d)}},1s:{\'2h-1i\':o(a,b,c){J(D i=0,W=[],E;E=a[i];i++){C(L.1r.4m(E))2e;W.O(E)}B W},\'1z-1i\':o(a,b,c){J(D i=0,W=[],E;E=a[i];i++){C(L.1r.4n(E))2e;W.O(E)}B W},\'4w-1i\':o(a,b,c){D h=L.1r;J(D i=0,W=[],E;E=a[i];i++)C(!h.4m(E)&&!h.4n(E))W.O(E);B W},\'1n-1i\':o(a,b,c){B L.1s.1n(a,b,c)},\'1n-1z-1i\':o(a,b,c){B L.1s.1n(a,b,c,1c)},\'1n-1G-1f\':o(a,b,c){B L.1s.1n(a,b,c,1d,1c)},\'1n-1z-1G-1f\':o(a,b,c){B L.1s.1n(a,b,c,1c,1c)},\'2h-1G-1f\':o(a,b,c){B L.1s.1n(a,"1",c,1d,1c)},\'1z-1G-1f\':o(a,b,c){B L.1s.1n(a,"1",c,1c,1c)},\'4w-1G-1f\':o(a,b,c){D p=L.1s;B p[\'1z-1G-1f\'](p[\'2h-1G-1f\'](a,b,c),b,c)},8N:o(a,b,d){C(a==0)B b>0?[b]:[];B $R(1,d).2A([],o(c,i){C(0==(i-b)%a&&(i-b)/a>=0)c.O(i);B c})},1n:o(c,d,e,f,g){C(c.I==0)B[];C(d==\'8K\')d=\'2n+0\';C(d==\'8L\')d=\'2n+1\';D h=L.1r,W=[],6L=[],m;h.5t(c);J(D i=0,E;E=c[i];i++){C(!E.1L.2v){h.4I(E.1L,f,g);6L.O(E.1L)}}C(d.1g(/^\\d+$/)){d=3u(d);J(D i=0,E;E=c[i];i++)C(E.5u==d)W.O(E)}1b C(m=d.1g(/^(-?\\d*)?n(([+-])(\\d+))?/)){C(m[1]=="-")m[1]=-1;D a=m[1]?3u(m[1]):1;D b=m[2]?3u(m[2]):0;D k=L.1s.8N(a,b,c.I);J(D i=0,E,l=k.I;E=c[i];i++){J(D j=0;j<l;j++)C(E.5u==k[j])W.O(E)}}h.3S(c);h.3S(6L);B W},\'4b\':o(a,b,c){J(D i=0,W=[],E;E=a[i];i++){C(E.1k==\'!\'||(E.3F&&!E.2r.1g(/^\\s*$/)))2e;W.O(E)}B W},\'31\':o(a,b,c){D h=L.1r,cB,m;D d=V L(b).4q(c);h.5t(d);J(D i=0,W=[],E;E=a[i];i++)C(!E.2v)W.O(E);h.3S(d);B W},\'8J\':o(a,b,c){J(D i=0,W=[],E;E=a[i];i++)C(!E.2c)W.O(E);B W},\'2c\':o(a,b,c){J(D i=0,W=[],E;E=a[i];i++)C(E.2c)W.O(E);B W},\'3l\':o(a,b,c){J(D i=0,W=[],E;E=a[i];i++)C(E.3l)W.O(E);B W}},5r:{\'=\':o(a,v){B a==v},\'!=\':o(a,v){B a!=v},\'^=\':o(a,v){B a.7g(v)},\'$=\':o(a,v){B a.7h(v)},\'*=\':o(a,v){B a.1p(v)},\'~=\':o(a,v){B(\' \'+a+\' \').1p(\' \'+v+\' \')},\'|=\':o(a,v){B(\'-\'+a.1X()+\'-\').1p(\'-\'+v.1X()+\'-\')}},8O:o(a,b){D c=V L(b).4q(),h=L.1r;h.5t(c);J(D i=0,W=[],15;15=a[i];i++)C(15.2v)W.O(15);h.3S(c);B W},3H:o(a,b,c){C(1m b==\'cC\'){c=b;b=1d}B L.8O(a,b||\'*\')[c||0]},6n:o(a,b){D c=b.1R(\',\'),b=[];c.78(/(([\\w#:.~>+()\\s-]+|\\*|\\[.*?\\])+)\\s*(,|$)/,o(m){b.O(m[1].3f())});D d=[],h=L.1r;J(D i=0,l=b.I,6M;i<l;i++){6M=V L(b[i].3f());h.1u(d,6M.4q(a))}B(l>1)?h.6F(d):d}});o $$(){B L.6n(11,$A(17))}D 1a={6N:o(a){$(a).6N();B a},8P:o(d,e){D f=d.2A({},o(a,b){C(!b.2c&&b.3n){D c=b.3n,1w=$(b).1Y();C(1w!=18){C(c 1t a){C(a[c].3g!=1E)a[c]=[a[c]];a[c].O(1w)}1b a[c]=1w}}B a});B e?f:1F.3h(f)}};1a.19={4y:o(a,b){B 1a.8P(1a.3T(a),b)},3T:o(c){B $A($(c).2D(\'*\')).2A([],o(a,b){C(1a.G.4z[b.1k.21()])a.O(G.M(b));B a})},cD:o(a,b,c){a=$(a);D d=a.2D(\'5v\');C(!b&&!c)B $A(d).20(G.M);J(D i=0,6O=[],I=d.I;i<I;i++){D e=d[i];C((b&&e.1f!=b)||(c&&e.3n!=c))2e;6O.O(G.M(e))}B 6O},6P:o(a){a=$(a);1a.3T(a).5U(\'6P\');B a},6Q:o(a){a=$(a);1a.3T(a).5U(\'6Q\');B a},8Q:o(b){B $(b).3T().7v(o(a){B a.1f!=\'5e\'&&!a.2c&&[\'5v\',\'2g\',\'6R\'].1p(a.1k.21())})},cE:o(a){a=$(a);a.8Q().8R();B a},4W:o(a,b){a=$(a),b=N.2m(b||{});D c=b.2C;b.2C=a.4y(1c);C(c){C(1m c==\'2B\')c=c.4L();N.M(b.2C,c)}C(a.2H(\'1K\')&&!b.1K)b.1K=a.1K;B V 1h.3C(a.6o(\'cF\'),b)}};1a.G={6S:o(a){$(a).6S();B a},2g:o(a){$(a).2g();B a}};1a.G.19={4y:o(a){a=$(a);C(!a.2c&&a.3n){D b=a.1Y();C(b!=1l){D c={};c[a.3n]=b;B 1F.3h(c)}}B\'\'},1Y:o(a){a=$(a);D b=a.1k.21();B 1a.G.4z[b](a)},7x:o(a){$(a).1w=\'\';B a},cG:o(a){B $(a).1w!=\'\'},8R:o(a){a=$(a);1P{a.6S();C(a.2g&&(a.1k.21()!=\'5v\'||![\'6T\',\'6N\',\'cH\'].1p(a.1f)))a.2g()}1V(e){}B a},6P:o(a){a=$(a);a.cI();a.2c=1c;B a},6Q:o(a){a=$(a);a.2c=1d;B a}};D cJ=1a.G;D $F=1a.G.19.1Y;1a.G.4z={5v:o(a){45(a.1f.21()){1I\'8S\':1I\'8T\':B 1a.G.4z.8U(a);6x:B 1a.G.4z.6R(a)}},8U:o(a){B a.3l?a.1w:18},6R:o(a){B a.1w},2g:o(a){B 7[a.1f==\'2g-cK\'?\'8V\':\'8W\'](a)},8V:o(a){D b=a.cL;B b>=0?7.6U(a.14[b]):18},8W:o(a){D b,I=a.I;C(!I)B 18;J(D i=0,b=[];i<I;i++){D c=a.14[i];C(c.cM)b.O(7.6U(c))}B b},6U:o(a){B G.M(a).2H(\'1w\')?a.1w:a.2q}};1O.5w=o(){};1O.5w.U={26:o(a,b,c){7.3c=b;7.15=$(a);7.3v=c;7.32=7.1Y();7.3d()},3d:o(){75(7.3e.1J(7),7.3c*5I)},3e:o(){D a=7.1Y();D b=(\'2B\'==1m 7.32&&\'2B\'==1m a?7.32!=a:1S(7.32)!=1S(a));C(b){7.3v(7.15,a);7.32=a}}};1a.G.5x=1C.1D();1a.G.5x.U=N.M(V 1O.5w(),{1Y:o(){B 1a.G.1Y(7.15)}});1a.5x=1C.1D();1a.5x.U=N.M(V 1O.5w(),{1Y:o(){B 1a.4y(7.15)}});1O.3a=o(){};1O.3a.U={26:o(a,b){7.15=$(a);7.3v=b;7.32=7.1Y();C(7.15.1k.21()==\'5D\')7.8X();1b 7.3d(7.15)},6V:o(){D a=7.1Y();C(7.32!=a){7.3v(7.15,a);7.32=a}},8X:o(){1a.3T(7.15).1e(7.3d.1J(7))},3d:o(a){C(a.1f){45(a.1f.21()){1I\'8S\':1I\'8T\':1x.3I(a,\'cN\',7.6V.1J(7));1y;6x:1x.3I(a,\'cO\',7.6V.1J(7));1y}}}};1a.G.3a=1C.1D();1a.G.3a.U=N.M(V 1O.3a(),{1Y:o(){B 1a.G.1Y(7.15)}});1a.3a=1C.1D();1a.3a.U=N.M(V 1O.3a(),{1Y:o(){B 1a.4y(7.15)}});C(!1j.1x){D 1x=V N()}N.M(1x,{cP:8,cQ:9,cR:13,cS:27,cT:37,cU:38,cV:39,cW:40,cX:46,cY:36,cZ:35,d0:33,d1:34,15:o(a){B $(a.d2||a.d3)},d4:o(a){B(((a.8Y)&&(a.8Y==1))||((a.6T)&&(a.6T==1)))},d5:o(a){B a.d6||(a.d7+(11.5y.3U||11.1T.3U))},d8:o(a){B a.d9||(a.da+(11.5y.3V||11.1T.3V))},5J:o(a){C(a.8Z){a.8Z();a.db()}1b{a.dc=1d;a.dd=1c}},3H:o(a,b){D c=1x.15(a);1o(c.1L&&(!c.1k||(c.1k.1X()!=b.1X())))c=c.1L;B c},2w:1d,90:o(a,b,c,d){C(!7.2w)7.2w=[];C(a.91){7.2w.O([a,b,c,d]);a.91(b,c,d)}1b C(a.3Y){7.2w.O([a,b,c,d]);a.3Y(\'3E\'+b,c)}},92:o(){C(!1x.2w)B;J(D i=0,I=1x.2w.I;i<I;i++){1x.59.2l(7,1x.2w[i]);1x.2w[i][0]=18}1x.2w=1d},3I:o(a,b,c,d){a=$(a);d=d||1d;C(b==\'93\'&&(12.1Z.3r||a.3Y))b=\'94\';1x.90(a,b,c,d)},59:o(a,b,c,d){a=$(a);d=d||1d;C(b==\'93\'&&(12.1Z.3r||a.3Y))b=\'94\';C(a.95){a.95(b,c,d)}1b C(a.96){1P{a.96(\'3E\'+b,c)}1V(e){}}}});C(12.1Z.3X)1x.3I(1j,\'de\',1x.92,1d);D 2G={97:1d,6W:o(){7.98=1j.df||11.5y.3U||11.1T.3U||0;7.99=1j.dg||11.5y.3V||11.1T.3V||0},9a:o(a){D b=0,1N=0;3W{b+=a.3V||0;1N+=a.3U||0;a=a.1L}1o(a);B[1N,b]},4o:o(a){D b=0,1N=0;3W{b+=a.3p||0;1N+=a.3q||0;a=a.2x}1o(a);B[1N,b]},9b:o(a){D b=0,1N=0;3W{b+=a.3p||0;1N+=a.3q||0;a=a.2x;C(a){C(a.1k==\'9c\')1y;D p=G.1M(a,\'1A\');C(p==\'5f\'||p==\'3k\')1y}}1o(a);B[1N,b]},2x:o(a){C(a.2x)B a.2x;C(a==11.1T)B a;1o((a=a.1L)&&a!=11.1T)C(G.1M(a,\'1A\')!=\'6u\')B a;B 11.1T},dh:o(a,x,y){C(7.97)B 7.9d(a,x,y);7.4A=x;7.4B=y;7.24=7.4o(a);B(y>=7.24[1]&&y<7.24[1]+a.3L&&x>=7.24[0]&&x<7.24[0]+a.3K)},9d:o(a,x,y){D b=7.9a(a);7.4A=x+b[0]-7.98;7.4B=y+b[1]-7.99;7.24=7.4o(a);B(7.4B>=7.24[1]&&7.4B<7.24[1]+a.3L&&7.4A>=7.24[0]&&7.4A<7.24[0]+a.3K)},di:o(a,b){C(!a)B 0;C(a==\'dj\')B((7.24[1]+b.3L)-7.4B)/b.3L;C(a==\'dk\')B((7.24[0]+b.3K)-7.4A)/b.3K},6X:o(a){D b=0,1N=0;D c=a;3W{b+=c.3p||0;1N+=c.3q||0;C(c.2x==11.1T)C(G.1M(c,\'1A\')==\'3k\')1y}1o(c=c.2x);c=a;3W{C(!1j.4C||c.1k==\'9c\'){b-=c.3V||0;1N-=c.3U||0}}1o(c=c.1L);B[1N,b]},2m:o(a,b){D c=N.M({9e:1c,9f:1c,9g:1c,9h:1c,3p:0,3q:0},17[2]||{});a=$(a);D p=2G.6X(a);b=$(b);D d=[0,0];D e=18;C(G.1M(b,\'1A\')==\'3k\'){e=2G.2x(b);d=2G.6X(e)}C(e==11.1T){d[0]-=11.1T.3q;d[1]-=11.1T.3p}C(c.9e)b.Y.2T=(p[0]-d[0]+c.3q)+\'2j\';C(c.9f)b.Y.2S=(p[1]-d[1]+c.3p)+\'2j\';C(c.9g)b.Y.2Q=a.3K+\'2j\';C(c.9h)b.Y.2P=a.3L+\'2j\'},dl:o(a){a=$(a);C(a.Y.1A==\'3k\')B;2G.6W();D b=2G.9b(a);D c=b[1];D d=b[0];D e=a.8h;D f=a.8i;a.9i=d-3J(a.Y.2T||0);a.9j=c-3J(a.Y.2S||0);a.9k=a.Y.2Q;a.9l=a.Y.2P;a.Y.1A=\'3k\';a.Y.2S=c+\'2j\';a.Y.2T=d+\'2j\';a.Y.2Q=e+\'2j\';a.Y.2P=f+\'2j\'},dm:o(a){a=$(a);C(a.Y.1A==\'5f\')B;2G.6W();a.Y.1A=\'5f\';D b=3J(a.Y.2S||0)-(a.9j||0);D c=3J(a.Y.2T||0)-(a.9i||0);a.Y.2S=b+\'2j\';a.Y.2T=c+\'2j\';a.Y.2P=a.9l;a.Y.2Q=a.9k}};C(12.1Z.3r){2G.4o=o(a){D b=0,1N=0;3W{b+=a.3p||0;1N+=a.3q||0;C(a.2x==11.1T)C(G.1M(a,\'1A\')==\'3k\')1y;a=a.2x}1o(a);B[1N,b]}}G.8s();',62,829,'|||||||this|||||||||||||||||function|||||||||||||return|if|var|node||Element||length|for||Selector|extend|Object|push||||||prototype|new|results||style|||document|Prototype||options|element||arguments|null|Methods|Form|else|true|false|each|type|match|Ajax|child|window|tagName|undefined|typeof|nth|while|include|transport|handlers|pseudos|in|concat|replace|value|Event|break|last|position|xpath|Class|create|Array|Hash|of|inspect|case|bind|method|parentNode|getStyle|valueL|Abstract|try|toJSON|join|String|body|Insertion|catch|RegExp|toUpperCase|getValue|Browser|map|toLowerCase|Template|Enumerable|offset|evaluate|initialize||toString|gsub|childNodes|toArray|disabled|div|continue|_each|select|first|key|px|matcher|apply|clone||args|stripScripts|text|innerHTML|onComplete|nodeType|className|_counted|observers|offsetParent|createElement|throw|inject|string|parameters|getElementsByTagName|ByTag|display|Position|hasAttribute|le|emptyFunction|toPaddedString|source|test|success|id|height|width|opacity|top|left|table|tbody|range|expression|descendant|sibling||not|lastValue||||||||EventObserver|BrowserFeatures|frequency|registerCallback|onTimerEvent|strip|constructor|toQueryString|setTimeout|decay|absolute|checked|_cache|name|formula|offsetTop|offsetLeft|WebKit|indexOf|values|Number|callback|timer|slice|evalScripts|split|add|Responders|Request|url|on|firstChild|nextSibling|findElement|observe|parseFloat|offsetWidth|offsetHeight|_overflow|Heading|insertContent|initializeRange|ps|adjacent|unmark|getElements|scrollLeft|scrollTop|do|IE|attachEvent|navigator||userAgent|ElementExtensions|HTMLElement|__proto__|switch||object|nodeValue|substring|_|empty|pluck|criteria|remove|start|responders|post|dispatchException|contains|cache|nextSiblings|previousElementSibling|nextElementSibling|cumulativeOffset|_flag|findElements|following|laterSibling|attrPresence|attr|pseudo|only|nodeClassName|serialize|Serializers|xcomp|ycomp|opera|Gecko|ScriptFragment|shift|times|currentlyExecuting|index|eval|escapeHTML|toQueryParams|camelize|charAt|evalJSON|reverse|ObjectRange|dispatch|onCreate|Base|setOptions|asynchronous|request|status|json|responseText|container|getElementsByClassName|Simulated|none|recursivelyCollect|_attributeTranslations|names|classNames|ClassNames|stopObserving|descendantOf|cssFloat|auto|setOpacity|hidden|relative|overflow|filter|alpha|TBODY|TR|depth|tr|_getAttr|copy|content|patterns|operators|count|mark|nodeIndex|input|TimedObserver|Observer|documentElement|Version|Opera|XPath|SpecificElementExtensions|form|script|instanceof|ownerDocument|succ|1000|stop|interpret|callee|prepareReplacement|gi|len|capitalize|unfilterJSON|appendChild|slices|array|invoke|falses|_reverse|without|call|Test|end|getTransport|activeRequestCount|application|encoding|Complete|_complete|respondToReadyState|onStateChange|getHeader|Updater|failure|update|updater|elements|_getElementsByXPath|class|hasClassName|findOrStore|visible|removeChild|selectNodeContents|previousSiblings|findChildElements|readAttribute|getDimensions|float|styleFloat|00001|visibility|static|_madePositioned|_getStyle|default|THEAD|TD|TableSection|HTML|adjacency|insertBefore|set|unique|or|preceding|and|predicate|fragment|indexed|selector|reset|matchingInputs|disable|enable|textarea|focus|button|optionValue|onElementEvent|prepare|page|KHTML|JSONFilter|keys|Function|Try|these|PeriodicalExecuter|setInterval|specialChar|sub|scan|stripTags|img|extractScripts|unescapeHTML|decodeURIComponent|charCodeAt|JSON|startsWith|endsWith|blank|amp|lt|gt|with|Pattern|template|pattern|eachSlice|collect|detect|findAll|size|find|from|clear|flatten|arrayLength|merge|addPair|encodeURIComponent|delete|exclusive|XMLHttpRequest|ActiveXObject|XMLHTTP|register|contentType|Events|get|onreadystatechange|setRequestHeaders|overrideMimeType|readyState|xml|Content|2005|requestHeaders|evalResponse|onException|updateContent|insertion|PeriodicalUpdater|updateComplete|lastText|_extended|toggle|hide|show|outerHTML|createRange|createContextualFragment|attribute|ancestors|descendants|firstDescendant|immediateDescendants|previousSibling|attributes|getAttribute|scrollTo|clientWidth|clientHeight|bottom|right|currentStyle|100|td|readonly|title|getAttributeNode|specified|addMethods|TEXTAREA|findDOMClass|Mod|TableCol|TableCell|insertAdjacentHTML|contentFromAnonymousTable|Before|Top|collapse|Bottom|After|compileMatcher|compileXPathMatcher|root|local|enabled|even|odd|byClassName|getIndices|matchElements|serializeElements|findFirstElement|activate|checkbox|radio|inputSelector|selectOne|selectMany|registerFormCallbacks|which|preventDefault|_observeAndCache|addEventListener|unloadCache|keypress|keydown|removeEventListener|detachEvent|includeScrollOffsets|deltaX|deltaY|realOffset|positionedOffset|BODY|withinIncludingScrolloffsets|setLeft|setTop|setWidth|setHeight|_originalLeft|_originalTop|_originalWidth|_originalHeight|AppleWebKit|u0001|uFFFF|secure|RangeError|unknown|boolean|bindAsEventListener|event|toColorPart|isFinite|Date|getFullYear|getMonth|getDate|getHours|getMinutes|getSeconds|clearInterval|finally|truncate|im|data|fromCharCode|underscore|dasherize|x00|x1f|u00|Eaeflnr|SyntaxError|Badly|formed|lastIndexOf|parseQuery|createTextNode|Error|is|deprecated|use|instead|all|any|grep|inGroupsOf|max|min|partition|reject|sortBy|sort|zip|pop|member|entries|NodeList|compact|reduce|uniq|foo|bar|Msxml2|Microsoft|unregister|www|urlencoded|UTF|Uninitialized|Loading|Loaded|Interactive|_method|Konqueror|Safari|open|postBody|send|Requested|With|Accept|javascript|html|charset|Connection|close|setRequestHeader|200|300|Success|Failure|java|ecma|getResponseHeader|clearTimeout|getElementById|XPathResult|ORDERED_NODE_SNAPSHOT_TYPE|snapshotLength|snapshotItem|replaceChild|siblings|up|down|previous|next|getElementsBySelector|getHeight|getWidth|addClassName|removeClassName|toggleClassName|cleanWhitespace|defaultView|getComputedStyle|getOpacity|setStyle|block|makePositioned|undoPositioned|makeClipping|undoClipping|childOf|childElements|999999|colspan|colSpan|rowspan|rowSpan|valign|vAlign|datetime|dateTime|accesskey|accessKey|tabindex|tabIndex|enctype|encType|maxlength|maxLength|readOnly|longdesc|longDesc|cssText|href|src|multiple|FORM|INPUT|SELECT|OPTGROUP|OptGroup|TextArea|Paragraph|FIELDSET|FieldSet|UL|UList|OL|OList|DL|DList|DIR|Directory|H1|H2|H3|H4|H5|H6|Quote|INS|DEL|Anchor|IMG|Image|CAPTION|TableCaption|COL|COLGROUP|TFOOT|TableRow|TH|FRAMESET|FrameSet|IFRAME|IFrame|Toggle|beforeBegin|setStartBefore|afterBegin|beforeEnd|afterEnd|setStartAfter|starts|translate|mod|en|dis|abled|children|selectorType|number|getInputs|focusFirstElement|action|present|submit|blur|Field|one|selectedIndex|selected|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|target|srcElement|isLeftClick|pointerX|pageX|clientX|pointerY|pageY|clientY|stopPropagation|returnValue|cancelBubble|unload|pageXOffset|pageYOffset|within|overlap|vertical|horizontal|absolutize|relativize'.split('|'),0,{}))

/*
*
* 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.
* * 
*
*
* FastInit
* http://tetlaw.id.au/view/javascript/fastinit
* Andrew Tetlaw
* Version 1.4.1 (2007-03-15)
* Based on:
* http://dean.edwards.name/weblog/2006/03/faster
* http://dean.edwards.name/weblog/2006/06/again/
* Help from:
* http://www.cherny.com/webdev/26/domloaded-object-literal-updated
* 
*/
var FastInit = {
	onload : function() {
		if (FastInit.done) { return; }
		FastInit.done = true;
		for(var x = 0, al = FastInit.f.length; x < al; x++) {
			FastInit.f[x]();
		}
	},
	addOnLoad : function() {
		var a = arguments;
		for(var x = 0, al = a.length; x < al; x++) {
			if(typeof a[x] === 'function') {
				if (FastInit.done ) {
					a[x]();
				} else {
					FastInit.f.push(a[x]);
				}
			}
		}
	},
	listen : function() {
		if (/WebKit|khtml/i.test(navigator.userAgent)) {
			FastInit.timer = setInterval(function() {
				if (/loaded|complete/.test(document.readyState)) {
					clearInterval(FastInit.timer);
					delete FastInit.timer;
					FastInit.onload();
				}}, 10);
		} else if (document.addEventListener) {
			document.addEventListener('DOMContentLoaded', FastInit.onload, false);
		} else if(!FastInit.iew32) {
			if(window.addEventListener) {
				window.addEventListener('load', FastInit.onload, false);
			} else if (window.attachEvent) {
				return window.attachEvent('onload', FastInit.onload);
			}
		}
	},
	f:[],done:false,timer:null,iew32:false
};
/*@cc_on @*/
/*@if (@_win32)
FastInit.iew32 = true;
document.write('<script id="__ie_onload" defer src="' + ((location.protocol == 'https:') ? '//0' : 'javascript:void(0)') + '"><\/script>');
document.getElementById('__ie_onload').onreadystatechange = function(){if (this.readyState == 'complete') { FastInit.onload(); }};
/*@end @*/
FastInit.listen();

aCContact = {
init: function()
	{
        if($('Country_auto_complete'))
		{
          new Ajax.Autocompleter('Country', 'Country_auto_complete', '/contact.keylist.php', {autoSelect: 'false'});
        }
		
		if($('Service_Country_auto_complete'))
		{
          new Ajax.Autocompleter('Service_Country', 'Service_Country_auto_complete', '/contact.keylist.php', {autoSelect: 'false'});
        }

		if($('State_auto_complete'))
		{
           if( 'Canada' === $F('Sales_Country') ){
		   		var param = '?c=1';
		   }else{
		   		var param = '';
		   }
			   new Ajax.Autocompleter('State_Province', 'State_auto_complete', '/contact.keylist.php' +  param, {autoSelect: 'false'});
		}

		if($('City_auto_complete'))
		{
          new Ajax.Autocompleter('City', 'City_auto_complete', '/contact.keylist.php', {
		  							autoSelect: 'true',
									minChars: '2',
									afterUpdateElement: aCContact.ajaxUpdateFields});
        }

		if($('Sales_auto_complete'))
		{
			new Ajax.Autocompleter('contactName', 'Sales_auto_complete', '/contact.keylist.php', {autoSelect: 'false'});
		}

		//give first form element focus
		if(document.forms[1])
		{

			$$('#contact input[type=text]').each(function(el)
			{
				el.observe('focus',function(el){
					Event.element(el).setStyle({ background:'#f3ba21'} );
				});

				el.observe('blur',function(el){
					Event.element(el).setStyle({
						backgroundImage:'url(/img/forminput.gif)'});
				});
			});
			
			// IE Fix: Remove backgrounds from radios and checkboxes
			var items = $$('#contact input[type!=text]');						//get all inputs which are not text (i.e. checkbox, radio & submit)
			items.pop();														//remove last item (= submit btn)
			items.invoke('setStyle',{background:'none'});
		}
    },

	ajaxUpdateFields: function(field, el)
			{
					var city  		   = field.value;										//get the city name
					var stateClassName = 'informal';
					var urlState	   = 'contact.fillstate.php';
	
					// search for the text inside the SPAN named 'informal' (i.e. the abbriviation of the state
					el.descendants().each(function(el)
					{
						if(stateClassName == el.className)
						{
							//console.log(e.innerHTML);	// innerHTML is similar to 'firstChild.nodeValue'
							var myAjax = new Ajax.Request( urlState, { method: 'get',
														   parameters: 's=' + el.innerHTML,
														   onComplete: aCContact.fillState });
							if(el.innerHTML.match(/.{4,39}/))     // min. and max length of city name
							{
								$('Postal_Code').value = el.innerHTML;
								$('Email').focus();
							}
						}
					});
			},

	fillState:	function(request)
		{
			$('State_Province').value = request.responseText;
			//$('Country').value = 'United States of America';
	
		}

};

/**
*	Hides 'Other' fields
*/
var SingAttend = Class.create();
SingAttend.prototype = {
	initialize: function()
	{
		if( null == $('Chip_Material_Other') ) { return; }		
		$('Application').focus();
		this.hide_lis();
		this.toggleDescItem	= this.toggleDesc.bindAsEventListener(this);
		$$('.dbdet select').each(function(e){
									e.observe('click', this.toggleDescItem);
								}.bind(this)
							);
	},
	
	hide_lis: function()
	{
		$$('ol.otherwrap li:nth-child(2)').invoke('hide');			
	},
	
	toggleDesc: function(e)
	{
		this.select_tag = Event.findElement(e, 'select');
		this.select_length = $(this.select_tag).getElementsBySelector('option').length;
		if(this.select_length - 1 == this.select_tag.value){
			this.show_li = $(this.select_tag).up('li').next().show();
			$(this.show_li).getElementsBySelector('input')[0].focus();
		}else{
			this.hide_lis();
		}
	}
}

var menuHilight = {
init: 	function(){	
			var menuItems = ['about','service','spares','products'];
			
			var url = document.location.href;				
			var subdirs = [];
			url.scan(/[A-Za-z0-9_-]+/, function(m){ subdirs.push(m[0]); } );  //seperate url at each word
	
			var navlinks = $$('#nav a');
            
            navlinks.each( function(e){
								var page = e.href.substring( e.href.lastIndexOf('/') + 1 );
								if('#' == page){page = 'products'};
								
                                subdirs.each( function(dir){									
                                
                                    if(dir == page)
									{	
                                        e.setStyle( {backgroundColor:'#f3ba21'} );
										
										var partClass = e.className.split(' ');
							
                                        partClass 	  = partClass[0];
										
										if( menuItems.indexOf(partClass) != -1 )
										{ // if class name exists in menuItems array, replace image											
											e.setStyle( {background: 'url(/img/nav_' + partClass +'_o.gif) top left no-repeat'} );
										}
									}
								});
								}
							);
	}
};

/**
* Workaround for target="_blank"
*/ 
var TargetBlank = Class.create();
TargetBlank.prototype = {
	initialize: function()
	{
		$$('a[rel="external"]').each(function(e){e.target='_blank';});
	}
}

/**
*	Go back one page
*/
var HistoryBack = Class.create();
HistoryBack.prototype = {
	initialize: function()
	{
		if( null == $('back') ) { return; }
		
		Event.observe('back','click', function(e){
						history.back(-1);												   
						Event.stop(e);
											   }
					 );
		
		Event.observe('print','click', function(e){
						window.print();												   
						Event.stop(e);
											   }
					 );		
	}
}

function checkImages() {
	if ( '250' != $('imgrep').offsetWidth ) {
      $$('a').invoke('setStyle',{textIndent:"0"} );
    }
}

/**
* Alternate colors for rows in tables
*/
var AlternateRows = Class.create();
AlternateRows.prototype = {
	initialize: function(){
		$$('table tbody tr:nth-child(even)').invoke('addClassName','even');
	}
};

/* MNEU */
function menuInit() {
	var uls = document.getElementsByTagName('ul');
    for (var u = 0; u < uls.length; u++) {
        if (uls[u].className.search(/\bslidingmenu\b/) == -1) {continue}
		var lis = uls[u].getElementsByTagName('li');
	    for (var i = 0; i < lis.length; i++) {
	      var node = lis[i];
	      if (node.nodeName.toLowerCase() == 'li' &&
	          node.getElementsByTagName('ul').length > 0) {
	        Event.observe(node, 'mouseover', getMoverFor(node));
	        Event.observe(node, 'mouseout', getMoutFor(node));
	        node.getElementsBySelector('a').first().className += ' subheader';
	      }
	    }
  }
}

function getMoverFor(node) {
  return function(e) { mover(e, node); };
}

function getMoutFor(node) {
  return function(e) { mout(e, node); };
}

function mover(e, targetElement) {
  var el = window.event ? targetElement : e ? e.currentTarget : null;
  if (!el){ return }
  clearTimeout(el.outTimeout);
  for (var i = 0; i < el.childNodes.length; i++) {
    var node = el.childNodes[i];
	if (node.nodeName.toLowerCase() == 'ul') {
	      node.style.display = 'block';
    }
  }
}

function mout(e, targetElement) {
  var el = window.event ? targetElement : e ? e.currentTarget : null;
  if (!el) {return}
  el.outTimeout = setTimeout(function() { mout2(el); }, 400);	/*Menu Delay Time*/
}

function mout2(el) {
  for (var i = 0; i < el.childNodes.length; i++) {
    var node = el.childNodes[i];
    if (node.nodeName.toLowerCase() == 'ul') {
      node.style.display = 'none';
    }
  }
}

/* Image Scroller */
var cF = {
	init: function(){
		if(typeof(objJSON) !== 'undefined')
		{
			Event.observe('next','click', cF.updatePic);
			Event.observe('prev','click', cF.updatePic);
			var quote = $('replace').getElementsBySelector('p')[0];
			/*quote.setStyle({height:'260px'});
			if(quote != ''){
				quote.setStyle({height:'auto'});
			}*/
		}
		
		if($('replace')){
			initLightbox();
		}
},

	updatePic: function(e) {
		var url = $('cfimg').src;
		var d 	= 0;		// change image file path no/yes

		// checks if current url is not english version
		if ( -1 !== document.URL.indexOf('/de/') ||
			-1 !== document.URL.indexOf('/cn/') ||
			-1 !== document.URL.indexOf('/tw/') ||
			-1 !== document.URL.indexOf('/jp/')
			) 
		{	
				var d = 1;	
		}

		var i = url.substring(url.lastIndexOf('/') + 1 ,url.length - 4); // find name of image and remove ". jpg"
		var f = Event.element(e).parentNode.id; // "next" or "prev" click
		var ind = 0; // index of JSON object
		var p = ''; //name of next pic to show
		var t = ''; //title of next pic to show
		var l = 0;  // number of pictures
		var q = ''; //quote

			
			
		objJSON.pictures.each(function(e,ind)
		{
			if(e.name == i)
			{
				switch(f)
				{
					case 'next':
						ind++;
						if(ind > objJSON.pictures.length - 1){
							ind = 0;
						}
						break;
					case 'prev':
						ind--;
						if(ind < 0){
							ind = objJSON.pictures.length - 1;
						}
						break;
					default:
						break;
				}//end of switch					

				p = objJSON.pictures[ind].name;
				t = escape(objJSON.pictures[ind].title); //caption of pic
				i = objJSON.pictures[ind].id;
				l = objJSON.pictures.length;			
				q = escape(objJSON.pictures[ind].quote);
				if(q === 'undefined'){q = ''}
			}//enf of if
		});

		var ajax =  new Ajax.Updater('replace','/imgscrollc.php',{
							method:'post',
							parameters: 'p=' + p + 
										'&t=' + t +
										'&i=' + i +
										'&l=' + l + 
										'&q=' + q +
										'&d=' + d,
							onComplete: cF.init
							});
	}
}
 
FastInit.addOnLoad( aCContact.init,
					menuInit,
					menuHilight.init, 
					function() { new HistoryBack();
                			     if( document.getElementsByTagName('table').length > 0 ){new AlternateRows();};
								 if( $('First_Name') ){ 
								 	$('First_Name').focus();
								 }else if( $('Email') ){
			    			        $('Email').focus();
								 }else if( $('sinput') ){
			    			        $('sinput').focus();
								 };
								 if( $('shdesc') ){ new SearchDescriptions();};
								 new TargetBlank();

					}
);

Event.observe(window, "load", 
			  function(){
				checkImages();
			  }
);

// script.aculo.us effects.js v1.7.1_beta2, Sat Apr 28 15:20:12 CEST 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 controls.js v1.7.1_beta2, Sat Apr 28 15:20:12 CEST 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 builder.js v1.7.1_beta2, Sat Apr 28 15:20:12 CEST 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() + '"');
    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)));  
      } 
    });
  }
}


// lightwindow.js v2.0
//
// Copyright (c) 2007 stickmanlabs
// Author: Kevin P Miller | http://www.stickmanlabs.com
// 
// LightWindow is freely distributable under the terms of an MIT-style license.
//
// I don't care what you think about the file size...
//   Be a pro: 
//	    http://www.thinkvitamin.com/features/webapps/serving-javascript-fast
//      http://rakaz.nl/item/make_your_pages_load_faster_by_combining_and_compressing_javascript_and_css_files
//

/*-----------------------------------------------------------------------------------------------*/

if(typeof Effect == 'undefined')
  throw("lightwindow.js requires including script.aculo.us' effects.js library!");

// This will stop image flickering in IE6 when elements with images are moved
try {
	document.execCommand("BackgroundImageCache", false, true);
} catch(e) {}

var lightwindow = Class.create();	
lightwindow.prototype = {
	//
	//	Setup Variables
	//
	element : null,
	contentToFetch : null,
	windowActive : false,
	dataEffects : [],
	dimensions : {
		cruft : null,
		container : null,
		viewport : {
			height : null,
			width : null,
			offsetTop : null,
			offsetLeft : null
		}
	},
	pagePosition : {
		x : 0,
		y : 0
	},
	pageDimensions : {
		width : null,
		height : null
	},
	preloadImage : [],
	preloadedImage : [],
	galleries : [],
	resizeTo : {
		height : null,
		heightPercent : null,
		width : null,
		widthPercent : null,
		fixedTop : null,
		fixedLeft : null
	},
	scrollbarOffset : 18,
	navigationObservers : {
		previous : null,
		next : null
	},
	containerChange : {
		height : 0,
		width : 0
	},
	activeGallery : false,
	galleryLocation : {
		current : 0,
		total : 0
	},
	//
	//	Initialize the lightwindow.
	//
	initialize : function(options) {
		this.options = Object.extend({
			resizeSpeed : 6,
			contentOffset : {
				height : 20,
				width : 20
			},
			dimensions : {
				image : {height : 250, width : 250},
				page : {height : 250, width : 250},
				inline : {height : 250, width : 250},
				media : {height : 250, width : 250},
				external : {height : 250, width : 250},
				titleHeight : 25
			},
			classNames : {	
				standard : 'lightwindow',
				action : 'lightwindow_action'
			},
			fileTypes : {
				page : ['asp', 'aspx', 'cgi', 'cfm', 'htm', 'html', 'pl', 'php4', 'php3', 'php', 'php5', 'phtml', 'rhtml', 'shtml', 'txt', 'vbs', 'rb'],
				media : ['aif', 'aiff', 'asf', 'avi', 'divx', 'm1v', 'm2a', 'm2v', 'm3u', 'mid', 'midi', 'mov', 'moov', 'movie', 'mp2', 'mp3', 'mpa', 'mpa', 'mpe', 'mpeg', 'mpg', 'mpg', 'mpga', 'pps', 'qt', 'rm', 'ram', 'swf', 'viv', 'vivo', 'wav'],
				image : ['bmp', 'gif', 'jpg', 'png', 'tiff']
			},
			mimeTypes : {
				avi : 'video/avi',
				aif : 'audio/aiff',
				aiff : 'audio/aiff',
				gif : 'image/gif',
				bmp : 'image/bmp',
				jpeg : 'image/jpeg',
				m1v : 'video/mpeg',
				m2a : 'audio/mpeg',
				m2v : 'video/mpeg',
				m3u : 'audio/x-mpequrl',
				mid : 'audio/x-midi',
				midi : 'audio/x-midi',
				mjpg : 'video/x-motion-jpeg',
				moov : 'video/quicktime',
				mov : 'video/quicktime',
				movie : 'video/x-sgi-movie',
				mp2 : 'audio/mpeg',
				mp3 : 'audio/mpeg3',
				mpa : 'audio/mpeg',
				mpa : 'video/mpeg',
				mpe : 'video/mpeg',
				mpeg : 'video/mpeg',
				mpg : 'audio/mpeg',
				mpg : 'video/mpeg',
				mpga : 'audio/mpeg',
				pdf : 'application/pdf',
				png : 'image/png',
				pps : 'application/mspowerpoint',
				qt : 'video/quicktime',
				ram : 'audio/x-pn-realaudio-plugin',
				rm : 'application/vnd.rn-realmedia',
				swf	: 'application/x-shockwave-flash',
				tiff : 'image/tiff',
				viv : 'video/vivo',
				vivo : 'video/vivo',
				wav : 'audio/wav',
				wmv : 'application/x-mplayer2'			
			},	
			classids : {
				mov : 'clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B',
				swf : 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000',
				wmv : 'clsid:6BF52A52-394A-11d3-B153-00C04F79FAA6'
			},
			codebases : {
				mov : 'http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0',
				swf : 'http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0',
				wmv : 'http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=6,4,5,715'
			},	
			viewportPadding : 10,
			EOLASFix : 'swf,wmv,fla,flv',
			overlay : {
				opacity : 0.7,
				image : '/img/black.png',
				presetImage : '/img/black-70.png'
			},
			skin : 	{
				main : 	'<div id="lightwindow_container" >'+
							'<div id="lightwindow_title_bar" >'+
								'<div id="lightwindow_title_bar_inner" >'+
									'<span id="lightwindow_title_bar_title"></span>'+
									'<a id="lightwindow_title_bar_close_link" >close</a>'+
								'</div>'+
							'</div>'+
							'<div id="lightwindow_stage" >'+
								'<div id="lightwindow_contents" >'+
								'</div>'+
								'<div id="lightwindow_navigation" >'+
									'<a href="#" id="lightwindow_previous" >'+
										'<span id="lightwindow_previous_title"></span>'+
									'</a>'+
									'<a href="#" id="lightwindow_next" >'+
										'<span id="lightwindow_next_title"></span>'+
									'</a>'+
									'<iframe name="lightwindow_navigation_shim" id="lightwindow_navigation_shim" src="javascript:false;" frameBorder="0" scrolling="no"></iframe>'+
								'</div>'+								
								'<div id="lightwindow_galleries">'+
									'<div id="lightwindow_galleries_tab_container" >'+
										'<a href="#" id="lightwindow_galleries_tab" >'+
											'<span id="lightwindow_galleries_tab_span" class="up" >Galleries</span>'+
										'</a>'+
									'</div>'+
									'<div id="lightwindow_galleries_list" >'+
									'</div>'+
								'</div>'+
							'</div>'+
							'<div id="lightwindow_data_slide" >'+
								'<div id="lightwindow_data_slide_inner" >'+
									'<div id="lightwindow_data_details" >'+
										'<div id="lightwindow_data_gallery_container" >'+
											'<span id="lightwindow_data_gallery_current"></span>'+
											' of '+
											'<span id="lightwindow_data_gallery_total"></span>'+
										'</div>'+
										'<div id="lightwindow_data_author_container" >'+
											'by <span id="lightwindow_data_author"></span>'+
										'</div>'+
									'</div>'+
									'<div id="lightwindow_data_caption" >'+
									'</div>'+
								'</div>'+
							'</div>'+
						'</div>',	
				loading : 	'<div id="lightwindow_loading" >'+
								'<img src="/img/ajax-loading.gif" alt="loading" />'+
								'<span>Loading or <a href="javascript: myLightWindow.deactivate();">Cancel</a></span>'+
								'<iframe name="lightwindow_loading_shim" id="lightwindow_loading_shim" src="javascript:false;" frameBorder="0" scrolling="no"></iframe>'+
							'</div>',
				iframe : 	'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'+
							'<html xmlns="http://www.w3.org/1999/xhtml">'+
								'<body>'+
									'{body_replace}'+
								'</body>'+
							'</html>',
				gallery : {
					top :		'<div class="lightwindow_galleries_list">'+
									'<h1>{gallery_title_replace}</h1>'+
									'<ul>',
					middle : 			'<li>'+
											'{gallery_link_replace}'+
										'</li>',
					bottom : 		'</ul>'+
								'</div>'
				}
			},
			formMethod : 'get',
			hideFlash : false,
			hideGalleryTab : false,
			showTitleBar : true,
			animationHandler : false,
			navigationHandler : false,
			transitionHandler : false,
			finalAnimationHandler : false,
			formHandler : false,
			galleryAnimationHandler : false,
			showGalleryCount : true
		}, options || {});
		this.duration = ((11-this.options.resizeSpeed)*0.15);
		this._setupLinks();
		this._getScroll();
		this._getPageDimensions();
		this._browserDimensions();
		this._addLightWindowMarkup(false);
		this._setupDimensions(); 
		this.buildGalleryList();
	},
	//
	//	Activate the lightwindow.
	//
	activate : function(e, link){		
		// Clear out the window Contents
		this._clearWindowContents(true);
			
		// Add back in out loading panel
		this._addLoadingWindowMarkup();

		// Setup the element properties
		this._setupWindowElements(link);
		
		// Setup everything
		this._getScroll();
		this._browserDimensions();
		this._setupDimensions();
		this._toggleTroubleElements('hidden', false);
		this._displayLightWindow('block', 'hidden');
		this._setStatus(true);
		this._monitorKeyboard(true);
		this._prepareIE(true);
		this._loadWindow();
	},
	//
	//	Turn off the window
	//
	deactivate : function(){
		// The window is not active
		this.windowActive = false;
		
		// There is no longer a gallery active
		this.activeGallery = false;
		if (!this.options.hideGalleryTab) {
			this._handleGalleryAnimation(false);
		}
		
		// Kill the animation
		this.animating = false;
		
		// Clear our element
		this.element = null;
		
		// hide the window.
		this._displayLightWindow('none', 'visible');
		
		// Clear out the window Contents
		this._clearWindowContents(false);
		
		// Stop all animation
		var queue = Effect.Queues.get('lightwindowAnimation').each(function(e){e.cancel();});
		
		// Undo the setup
		this._prepareIE(false);
		this._setupDimensions();
		this._toggleTroubleElements('visible', false);	
		this._monitorKeyboard(false);	
	},
	//
	//  Initialize specific window
	//
	createWindow : function(element, attributes) {
		this._processLink($(element));
	},
	//
	//  Open a Window from a hash of attributes
	//
	activateWindow : function(options) {
		this.element = Object.extend({
			href : null,
			title : null,
			author : null,
			caption : null,
			rel : null,
			top : null,
			left : null,
			type : null,
			showImages : null,
			height : null,
			width : null,
			loadingAnimation : null,
			iframeEmbed : null,
			form : null
		}, options || {});
		
		// Set the window type
		this.contentToFetch = this.element.href;
		this.windowType = this.element.type ? this.element.type : this._fileType(this.element.href);	
		
		// Clear out the window Contents
		this._clearWindowContents(true);
			
		// Add back in out loading panel
		this._addLoadingWindowMarkup();
		
		// Setup everything
		this._getScroll();
		this._browserDimensions();
		this._setupDimensions();
		this._toggleTroubleElements('hidden', false);
		this._displayLightWindow('block', 'hidden');
		this._setStatus(true);
		this._monitorKeyboard(true);
		this._prepareIE(true);
		this._loadWindow();
	},
	//
	//  Fire off our Form handler
	//
	submitForm : function(e) {
		if (this.options.formHandler) {
			this.options.formHandler(e);
		} else {
			this._defaultFormHandler(e);
		}
	},
	//
	//	Reload the window with another location
	//
	openWindow : function(element) {
		var element = $(element);

		// The window is active
		this.windowActive = true;
		
		// Clear out the window Contents
		this._clearWindowContents(true);
		
		// Add back in out loading panel
		this._addLoadingWindowMarkup();
		
		// Setup the element properties
		this._setupWindowElements(element);

		this._setStatus(true);
		this._handleTransition();
	},
	//
	//  Navigate the window
	//
	navigateWindow : function(direction) {
		this._handleNavigation(false);
		if (direction == 'previous') {
			this.openWindow(this.navigationObservers.previous);
		} else if (direction == 'next'){ 
			this.openWindow(this.navigationObservers.next);
		}
	},
	//
	//  Build the Gallery List and Load it
	//
	buildGalleryList : function() {
		var output = '';
		var galleryLink;
		for (i in this.galleries) {
			if (typeof this.galleries[i] == 'object') {
				output += (this.options.skin.gallery.top).replace('{gallery_title_replace}', unescape(i));
				for (j in this.galleries[i]) {
					if (typeof this.galleries[i][j] == 'object') {						
						galleryLink = '<a href="#" id="lightwindow_gallery_'+i+'_'+j+'" >'+unescape(j)+'</a>';
						output += (this.options.skin.gallery.middle).replace('{gallery_link_replace}', galleryLink);
					}
				}
				output += this.options.skin.gallery.bottom;
			}
		}
		new Insertion.Top('lightwindow_galleries_list', output);
		
		// Attach Events
		for (i in this.galleries) {
			if (typeof this.galleries[i] == 'object') {
				for (j in this.galleries[i]) {
					if (typeof this.galleries[i][j] == 'object') {
						Event.observe($('lightwindow_gallery_'+i+'_'+j), 'click', this.openWindow.bind(this, this.galleries[i][j][0]), false);
						$('lightwindow_gallery_'+i+'_'+j).onclick = function() {return false;};	
					}
				}
			}
		}
	},
	// 
	//  Set Links Up
	//
	_setupLinks : function() {
		var links = $$('.'+this.options.classNames.standard);
		links.each(function(link) {
			this._processLink(link);
		}.bind(this));	
	},
	//
	//  Process a Link
	//
	_processLink : function(link) {
		if ((this._fileType(link.getAttribute('href')) == 'image' || this._fileType(link.getAttribute('href')) == 'media')) {
			if (gallery = this._getGalleryInfo(link.rel)) {
				if (!this.galleries[gallery[0]]) {
					this.galleries[gallery[0]] = new Array();
				}
				if (!this.galleries[gallery[0]][gallery[1]]) {
					this.galleries[gallery[0]][gallery[1]] = new Array();
				}
				this.galleries[gallery[0]][gallery[1]].push(link);
			}
		}
		
		// Take care of our inline content
		var url = link.getAttribute('href');
		if (url.indexOf('?') > -1) {
			url = url.substring(0, url.indexOf('?'));
		}
		
		var container = url.substring(url.indexOf('#')+1);
		if($(container)) {
			$(container).setStyle({
				display : 'none'
			});
		}
		
		Event.observe(link, 'click', this.activate.bindAsEventListener(this, link), false);
		link.onclick = function() {return false;};		
	},
	//
	//	Setup our actions
	//
	_setupActions : function() {
		var links = $$('#lightwindow_container .'+this.options.classNames.action);
		links.each(function(link) {
			Event.observe(link, 'click', this[link.getAttribute('rel')].bindAsEventListener(this, link), false);
			link.onclick = function() {return false;};
		}.bind(this));
	},
	//
	//	Add the markup to the page.
	//
	_addLightWindowMarkup : function(rebuild) {
		var overlay = Element.extend(document.createElement('div'));
		overlay.setAttribute('id', 'lightwindow_overlay');		
		// FF Mac has a problem with putting Flash above a layer without a 100% opacity background, so we need to use a pre-made
		if (Prototype.Browser.Gecko) {
			overlay.setStyle({
				backgroundImage: 'url('+this.options.overlay.presetImage+')',
				backgroundRepeat: 'repeat',
				height: this.pageDimensions.height+'px'
			});			
		} else {
			overlay.setStyle({
				opacity: this.options.overlay.opacity,
				backgroundImage: 'url('+this.options.overlay.image+')',
				backgroundRepeat: 'repeat',
				height: this.pageDimensions.height+'px'
			});
		}
		
		var lw = document.createElement('div');
		lw.setAttribute('id', 'lightwindow');
		lw.innerHTML = this.options.skin.main;
		
		var body = document.getElementsByTagName('body')[0];
		body.appendChild(overlay);
		body.appendChild(lw);	
				
		if ($('lightwindow_title_bar_close_link')) {
			Event.observe('lightwindow_title_bar_close_link', 'click', this.deactivate.bindAsEventListener(this));
			$('lightwindow_title_bar_close_link').onclick = function() {return false;};
		}
			
		Event.observe($('lightwindow_previous'), 'click', this.navigateWindow.bind(this, 'previous'), false);
		$('lightwindow_previous').onclick = function() {return false;};		
		Event.observe($('lightwindow_next'), 'click', this.navigateWindow.bind(this, 'next'), false);
		$('lightwindow_next').onclick = function() {return false;};

		if (!this.options.hideGalleryTab) {
			Event.observe($('lightwindow_galleries_tab'), 'click', this._handleGalleryAnimation.bind(this, true), false);
			$('lightwindow_galleries_tab').onclick = function() {return false;};
		}
		
		// Because we use position absolute, kill the scroll Wheel on animations
		if (Prototype.Browser.IE) {
			Event.observe(document, 'mousewheel', this._stopScrolling.bindAsEventListener(this), false);
		} else {
			Event.observe(window, 'DOMMouseScroll', this._stopScrolling.bindAsEventListener(this), false);
		}
				
		Event.observe(overlay, 'click', this.deactivate.bindAsEventListener(this), false);
		overlay.onclick = function() {return false;};
	},
	//
	//  Add loading window markup
	//
	_addLoadingWindowMarkup : function() {
		$('lightwindow_contents').innerHTML += this.options.skin.loading;
	},
	//
	//  Setup the window elements
	//
	_setupWindowElements : function(link) {
		this.element = link;
		this.element.title = null ? '' : link.getAttribute('title');
		this.element.author = null ? '' : link.getAttribute('author');
		this.element.caption = null ? '' : link.getAttribute('caption');
		this.element.rel = null ? '' : link.getAttribute('rel');
		this.element.params = null ? '' : link.getAttribute('params');

		// Set the window type
		this.contentToFetch = this.element.href;
		this.windowType = this._getParameter('lightwindow_type') ? this._getParameter('lightwindow_type') : this._fileType(this.contentToFetch);	
	},
	//
	//  Clear the window contents out
	//
	_clearWindowContents : function(contents) {
		// If there is an iframe, its got to go
		if ($('lightwindow_iframe')) {
			Element.remove($('lightwindow_iframe'));
		}

		// Stop playing an object if its still around
		if ($('lightwindow_media_primary')) {
			try {
				$('lightwindow_media_primary').Stop();
			} catch(e) {}
			Element.remove($('lightwindow_media_primary'));
		}

		// Stop playing an object if its still around		
		if ($('lightwindow_media_secondary')) {
			try {
				$('lightwindow_media_secondary').Stop();
			} catch(e) {}
			Element.remove($('lightwindow_media_secondary'));
		}
		
		this.activeGallery = false;
		this._handleNavigation(this.activeGallery);
		
		if (contents) {
			// Empty the contents
			$('lightwindow_contents').innerHTML = '';
			
			// Reset the scroll bars
			$('lightwindow_contents').setStyle({
				overflow: 'hidden'
			});		
			
			if (!this.windowActive) {
				$('lightwindow_data_slide_inner').setStyle({
					display: 'none'
				});

				$('lightwindow_title_bar_title').innerHTML = '';
			}

			// Because of browser differences and to maintain flexible captions we need to reset this height at close
			$('lightwindow_data_slide').setStyle({
				height: 'auto'
			});
		}
		
		this.resizeTo.height = null;
		this.resizeTo.width = null;
	},
	//
	//	Set the status of our animation to keep things from getting clunky
	//
	_setStatus : function(status) {
		this.animating = status;
		if (status) {
			Element.show('lightwindow_loading');
		}
		if (!(/MSIE 6./i.test(navigator.userAgent))) {
			this._fixedWindow(status);
		}
	},
	//
	//  Make this window Fixed
	//
	_fixedWindow : function(status) {
		if (status) {
			if (this.windowActive) {
				this._getScroll();
				$('lightwindow').setStyle({
					position: 'absolute',
					top: parseFloat($('lightwindow').getStyle('top'))+this.pagePosition.y+'px',
					left: parseFloat($('lightwindow').getStyle('left'))+this.pagePosition.x+'px'
				});		
			} else {
				$('lightwindow').setStyle({
					position: 'absolute'
				});						
			}
		} else {
			if (this.windowActive) {
				this._getScroll();
				$('lightwindow').setStyle({
					position: 'fixed',
					top: parseFloat($('lightwindow').getStyle('top'))-this.pagePosition.y+'px',
					left: parseFloat($('lightwindow').getStyle('left'))-this.pagePosition.x+'px'
				});		
			} else {
				if ($('lightwindow_iframe')) {
					// Ideally here we would set a 50% value for top and left, but Safari rears it ugly head again and we need to do it by pixels
					this._browserDimensions();
				}
				$('lightwindow').setStyle({
					position: 'fixed',
					top: (parseFloat(this._getParameter('lightwindow_top')) ? parseFloat(this._getParameter('lightwindow_top'))+'px' : this.dimensions.viewport.height/2+'px'),
					left: (parseFloat(this._getParameter('lightwindow_left')) ? parseFloat(this._getParameter('lightwindow_left'))+'px' : this.dimensions.viewport.width/2+'px')
				});
			}
		}
	},
	//
	//	Prepare the window for IE.
	//
	_prepareIE : function(setup) {
		if (Prototype.Browser.IE) {
			var height, overflowX, overflowY;
			if (setup) { 
				var height = '100%';
			} else {
				var height = 'auto';
			}
			var body = document.getElementsByTagName('body')[0];
			var html = document.getElementsByTagName('html')[0];
			html.style.height = body.style.height = height;
		}
	},
	_stopScrolling : function(e) {
		if (this.animating) {
			if (e.preventDefault) {
				e.preventDefault();
			}
			e.returnValue = false;		
		}
	},
	//
	//	Get the scroll for the page.
	//
	_getScroll : function(){
      	if(typeof(window.pageYOffset) == 'number') {
        	this.pagePosition.x = window.pageXOffset;
        	this.pagePosition.y = window.pageYOffset;
      	} else if(document.body && (document.body.scrollLeft || document.body.scrollTop)) {
	       	this.pagePosition.x = document.body.scrollLeft;
        	this.pagePosition.y = document.body.scrollTop;
		} else if(document.documentElement) {
        	this.pagePosition.x = document.documentElement.scrollLeft;
        	this.pagePosition.y = document.documentElement.scrollTop;
      	}
	},
	//
	//	Reset the scroll.
	//
	_setScroll : function(x, y) {
		document.documentElement.scrollLeft = x; 
		document.documentElement.scrollTop = y; 
	},
	//
	//	Hide Selects from the page because of IE.
	//     We could use iframe shims instead here but why add all the extra markup for one browser when this is much easier and cleaner
	//
	_toggleTroubleElements : function(visibility, content){
		
		if (content) {
			var selects = $('lightwindow_contents').getElementsByTagName('select');
		} else {
			var selects = document.getElementsByTagName('select');
		}
		
		for(var i = 0; i < selects.length; i++) {
			selects[i].style.visibility = visibility;
		}
		
		if (!content) {
			if (this.options.hideFlash){
				var objects = document.getElementsByTagName('object');
				for (i = 0; i != objects.length; i++) {
					objects[i].style.visibility = visibility;
				}
				var embeds = document.getElementsByTagName('embed');
				for (i = 0; i != embeds.length; i++) {
					embeds[i].style.visibility = visibility;
				}
			}
			var iframes = document.getElementsByTagName('iframe');
			for (i = 0; i != iframes.length; i++) {
				iframes[i].style.visibility = visibility;
			}
		}
	},
	// 
	//  Get the actual page size
	//
	_getPageDimensions : function() {
		var xScroll, yScroll;
		if (window.innerHeight && window.scrollMaxY) {	
			xScroll = document.body.scrollWidth;
			yScroll = window.innerHeight + window.scrollMaxY;
		} else if (document.body.scrollHeight > document.body.offsetHeight){ 
			xScroll = document.body.scrollWidth;
			yScroll = document.body.scrollHeight;
		} else { 
			xScroll = document.body.offsetWidth;
			yScroll = document.body.offsetHeight;
		}

		var windowWidth, windowHeight;
		if (self.innerHeight) {	
			windowWidth = self.innerWidth;
			windowHeight = self.innerHeight;
		} else if (document.documentElement && document.documentElement.clientHeight) { 
			windowWidth = document.documentElement.clientWidth;
			windowHeight = document.documentElement.clientHeight;
		} else if (document.body) { 
			windowWidth = document.body.clientWidth;
			windowHeight = document.body.clientHeight;
		}	

		if(yScroll < windowHeight){
			this.pageDimensions.height = windowHeight;
		} else { 
			this.pageDimensions.height = yScroll;
		}

		if(xScroll < windowWidth){	
			this.pageDimensions.width = windowWidth;
		} else {
			this.pageDimensions.width = xScroll;
		}
	},
	//
	//	Display the lightWindow.
	//
	_displayLightWindow : function(display, visibility) {
		$('lightwindow_overlay').style.display = $('lightwindow').style.display = $('lightwindow_container').style.display = display;	
		$('lightwindow_overlay').style.visibility = $('lightwindow').style.visibility = $('lightwindow_container').style.visibility = visibility;
	},
	//
	//	Setup Dimensions of lightwindow.

	//
	_setupDimensions : function() {

		var originalHeight, originalWidth;
		switch (this.windowType) {
			case 'page' :
				originalHeight = this.options.dimensions.page.height;
				originalWidth = this.options.dimensions.page.width;
				break;

			case 'image' :
				originalHeight = this.options.dimensions.image.height;
				originalWidth = this.options.dimensions.image.width;
				break;
				
			case 'media' :
				originalHeight = this.options.dimensions.media.height;
				originalWidth = this.options.dimensions.media.width;
				break;
			
			case 'external' : 
				originalHeight = this.options.dimensions.external.height;
				originalWidth = this.options.dimensions.external.width;
				break;
				
			case 'inline' :
				originalHeight = this.options.dimensions.inline.height;
				originalWidth = this.options.dimensions.inline.width;
				break;
				
			default :
				originalHeight = this.options.dimensions.page.height;
				originalWidth = this.options.dimensions.page.width;
				break;
				
		}

		var offsetHeight = this._getParameter('lightwindow_top') ? parseFloat(this._getParameter('lightwindow_top'))+this.pagePosition.y : this.dimensions.viewport.height/2+this.pagePosition.y;
		var offsetWidth = this._getParameter('lightwindow_left') ? parseFloat(this._getParameter('lightwindow_left'))+this.pagePosition.x : this.dimensions.viewport.width/2+this.pagePosition.x;
		
		// So if a theme has say shadowed edges, they should be consistant and take care of in the contentOffset
		$('lightwindow').setStyle({
			top: offsetHeight+'px',
			left: offsetWidth+'px'
		});
		
		$('lightwindow_container').setStyle({
			height: originalHeight+'px',
			width: originalWidth+'px',
			left: -(originalWidth/2)+'px',
			top: -(originalHeight/2)+'px'
		});

		$('lightwindow_contents').setStyle({
			height: originalHeight+'px',
			width: originalWidth+'px'
		});
	},
	//
	//	Get the type of file.
	//
	_fileType : function(url) {
		var image = new RegExp("[^\.]\.("+this.options.fileTypes.image.join('|')+")\s*$", "i");
		if (image.test(url)) return 'image';
		if (url.indexOf('#') > -1 && (document.domain == this._getDomain(url))) return 'inline';		
		if (url.indexOf('?') > -1) url = url.substring(0, url.indexOf('?'));
		var type = 'unknown';
		var page = new RegExp("[^\.]\.("+this.options.fileTypes.page.join('|')+")\s*$", "i");
		var media = new RegExp("[^\.]\.("+this.options.fileTypes.media.join('|')+")\s*$", "i");
		if (document.domain != this._getDomain(url)) type = 'external';
	  	if (media.test(url)) type = 'media';
		if (type == 'external' || type == 'media') return type;
	  	if (page.test(url) || url.substr((url.length-1), url.length) == '/') type = 'page';
		return type;
	},
	//
	//  Get file Extension
	//
	_fileExtension : function(url) {
		if (url.indexOf('?') > -1) {
			url = url.substring(0, url.indexOf('?'));
		}
		var extenstion = '';
		for (var x = (url.length-1); x > -1; x--) {
			if (url.charAt(x) == '.') {
				return extenstion;
			}
			extenstion = url.charAt(x)+extenstion;
		}
	},
	//
	//	Monitor the keyboard while this lightwindow is up
	//
	_monitorKeyboard : function(status) {
		if (status) document.onkeydown = this._eventKeypress.bind(this); 
		else document.onkeydown = '';
	},
	//
	//  Perform keyboard actions
	//
	_eventKeypress : function(e) {
		if (e == null) {
			var keycode = event.keyCode;
		} else {
			var keycode = e.which;
		}
		
		switch (keycode) { 
			case 27: 
				this.deactivate(); 
				break;
			
			case 13:
				return;
				
			default:
				break;
		}
	
		// Gotta stop those quick fingers
		if (this.animating) {
			return false;
		}
		
		switch (String.fromCharCode(keycode).toLowerCase()) {
			case 'p':
				if (this.navigationObservers.previous) {
					this.navigateWindow('previous');
				}
				break;
				
			case 'n':
				if (this.navigationObservers.next) {
					this.navigateWindow('next');
				}
				break;
				
			default:
				break;
		}
	},
	//
	//	Get Gallery Information
	//
	_getGalleryInfo : function(rel) {
		if (!rel) return false;
		if (rel.indexOf('[') > -1) {
			return new Array(escape(rel.substring(0, rel.indexOf('['))), escape(rel.substring(rel.indexOf('[')+1, rel.indexOf(']'))));
		} else {
			return false;
		}
	},
	//
	//	Get the domain from a string.
	//
	_getDomain : function(url) {    
        var leadSlashes = url.indexOf('//');
        var domainStart = leadSlashes+2;
        var withoutResource = url.substring(domainStart, url.length);
        var nextSlash = withoutResource.indexOf('/');
        var domain = withoutResource.substring(0, nextSlash);
		if (domain.indexOf(':') > -1){
			var portColon = domain.indexOf(':');
			domain = domain.substring(0, portColon);
       	}
		return domain;
    },
	//
	//	Get the value from the params attribute string.
	//
	_getParameter : function(parameter, parameters) {
		if (!this.element) return false;
		if (parameter == 'lightwindow_top' && this.element.top) {
			return unescape(this.element.top);
		} else if (parameter == 'lightwindow_left' && this.element.left) {
			return unescape(this.element.left);
		} else if (parameter == 'lightwindow_type' && this.element.type) {
			return unescape(this.element.type);
		} else if (parameter == 'lightwindow_show_images' && this.element.showImages) {
			return unescape(this.element.showImages);
		} else if (parameter == 'lightwindow_height' && this.element.height) {
			return unescape(this.element.height);
		} else if (parameter == 'lightwindow_width' && this.element.width) {
			return unescape(this.element.width);
		} else if (parameter == 'lightwindow_loading_animation' && this.element.loadingAnimation) {
			return unescape(this.element.loadingAnimation);
		} else if (parameter == 'lightwindow_iframe_embed' && this.element.iframeEmbed) {
			return unescape(this.element.iframeEmbed);
		} else if (parameter == 'lightwindow_form' && this.element.form) {
			return unescape(this.element.form);
		} else {
			if (!parameters) {
				if (this.element.params) parameters = this.element.params;
				else return;
			}
			var value;
			var parameterArray = parameters.split(',');
			var compareString = parameter+'=';
			var compareLength = compareString.length;
			for (var i = 0; i < parameterArray.length; i++) {
				if (parameterArray[i].substr(0, compareLength) == compareString) {
					var currentParameter = parameterArray[i].split('=');
					value = currentParameter[1];
					break;
				}
			}
			if (!value) return false;
			else return unescape(value);
		}
	},
	//
	//  Get the Browser Viewport Dimensions
	//
	_browserDimensions : function() {
		if (Prototype.Browser.IE) {
            this.dimensions.viewport.height = document.documentElement.clientHeight;
            this.dimensions.viewport.width = document.documentElement.clientWidth;   
        } else {
            this.dimensions.viewport.height = window.innerHeight;
            this.dimensions.viewport.width = document.width || document.body.offsetWidth;
        }
	},
	//
	//  Get the scrollbar offset, I don't like this method but there is really no other way I can find.
	//
	_getScrollerWidth : function() {
	    var scrollDiv = Element.extend(document.createElement('div'));
		scrollDiv.setAttribute('id', 'lightwindow_scroll_div');
		scrollDiv.setStyle({
			position: 'absolute',
			top: '-10000px',
			left: '-10000px',
			width: '100px',
			height: '100px',
			overflow: 'hidden'
		});



	    var contentDiv = Element.extend(document.createElement('div'));
		contentDiv.setAttribute('id', 'lightwindow_content_scroll_div');
		contentDiv.setStyle({
			width: '100%',
			height: '200px'
		});

	    scrollDiv.appendChild(contentDiv);

		var body = document.getElementsByTagName('body')[0];
		body.appendChild(scrollDiv);

	    var noScroll = $('lightwindow_content_scroll_div').offsetWidth;
	    scrollDiv.style.overflow = 'auto';
    	var withScroll = $('lightwindow_content_scroll_div').offsetWidth;

	   	Element.remove($('lightwindow_scroll_div'));

	    this.scrollbarOffset = noScroll-withScroll;
	},
	

	//
	//  Add a param to an object dynamically created
	//
	_addParamToObject : function(name, value, object, id) {
		var param = document.createElement('param');
		param.setAttribute('value', value);
		param.setAttribute('name', name);
		if (id) {
			param.setAttribute('id', id);
		}
		object.appendChild(param);
		return object;
	},
	//
	//  Get the outer HTML of an object CROSS BROWSER
	//
	_outerHTML : function(object) {
 		if (Prototype.Browser.IE) {
			return object.outerHTML;
		} else {
			var clone = object.cloneNode(true);
			var cloneDiv = document.createElement('div');
			cloneDiv.appendChild(clone);
			return cloneDiv.innerHTML;
		}
	},
	//
	//  Convert an object to markup
	//
	_convertToMarkup : function(object, closeTag) {
		var markup = this._outerHTML(object).replace('</'+closeTag+'>', '');
		if (Prototype.Browser.IE) {
			for (var i = 0; i < object.childNodes.length; i++){
				markup += this._outerHTML(object.childNodes[i]);
			}
			markup += '</'+closeTag+'>';
		}
		return markup;
	},
	//
	//  Depending what type of browser it is we have to append the object differently... DAMN YOU IE!!
	//
	_appendObject : function(object, closeTag, appendTo) {
		if (Prototype.Browser.IE) {
			appendTo.innerHTML += this._convertToMarkup(object, closeTag);
			
			// Fix the Eolas activate thing but only for specified media, for example doing this to a quicktime film breaks it.
			if (this.options.EOLASFix.indexOf(this._fileType(this.element.href)) > -1) {
				var objectElements = document.getElementsByTagName('object');
				for (var i = 0; i < objectElements.length; i++) {
					if (objectElements[i].getAttribute("data")) objectElements[i].removeAttribute('data');
					objectElements[i].outerHTML = objectElements[i].outerHTML;
					objectElements[i].style.visibility = "visible";
				}
			}
		} else {
			appendTo.appendChild(object);	
		}	
	},
	//
	//  Add in iframe
	//
	_appendIframe : function(scroll) {
		var iframe = document.createElement('iframe');
		iframe.setAttribute('id', 'lightwindow_iframe');
		iframe.setAttribute('name', 'lightwindow_iframe');
		iframe.setAttribute('src', 'about:blank');
		iframe.setAttribute('height', '100%');
		iframe.setAttribute('width', '100%');
		iframe.setAttribute('frameborder', '0');
		iframe.setAttribute('marginwidth', '0');
		iframe.setAttribute('marginheight', '0');
		iframe.setAttribute('scrolling', scroll);	
		
		this._appendObject(iframe, 'iframe', $('lightwindow_contents'));
	},
	//
	//  Write Content to the iframe using the skin
	//
	_writeToIframe : function(content) {
		var template = this.options.skin.iframe;
		template = template.replace('{body_replace}', content); 
		if ($('lightwindow_iframe').contentWindow){
			$('lightwindow_iframe').contentWindow.document.open();
			$('lightwindow_iframe').contentWindow.document.write(template);
			$('lightwindow_iframe').contentWindow.document.close();
		} else {
			$('lightwindow_iframe').contentDocument.open();
			$('lightwindow_iframe').contentDocument.write(template);
			$('lightwindow_iframe').contentDocument.close();
		}
	},
	//
	//  Load the window Information
	//  
	_loadWindow : function() {
		switch (this.windowType) {
			case 'image' :

				var current = 0;
				var images = [];
				this.checkImage = [];
				this.resizeTo.height = this.resizeTo.width = 0;
				this.imageCount = this._getParameter('lightwindow_show_images') ? parseInt(this._getParameter('lightwindow_show_images')) : 1;

				// If there is a gallery get it
				if (gallery = this._getGalleryInfo(this.element.rel)) {	
					for (current = 0; current < this.galleries[gallery[0]][gallery[1]].length; current++) {
						if (this.contentToFetch.indexOf(this.galleries[gallery[0]][gallery[1]][current].href) > -1) {
							break;
						}
					}
					if (this.galleries[gallery[0]][gallery[1]][current-this.imageCount]) {
						this.navigationObservers.previous = this.galleries[gallery[0]][gallery[1]][current-this.imageCount];
					} else {
						this.navigationObservers.previous = false;
					}
					if (this.galleries[gallery[0]][gallery[1]][current+this.imageCount]) {
						this.navigationObservers.next = this.galleries[gallery[0]][gallery[1]][current+this.imageCount];
					} else {
						this.navigationObservers.next = false;
					}
					
					this.activeGallery = true;
				} else {
					this.navigationObservers.previous = false;
					this.navigationObservers.next = false;					

					this.activeGallery = false;
				}
				
				for (var i = current; i < (current+this.imageCount); i++) {
		
					if (gallery && this.galleries[gallery[0]][gallery[1]][i]) {
						this.contentToFetch = this.galleries[gallery[0]][gallery[1]][i].href;
						
						this.galleryLocation = {current: (i+1)/this.imageCount, total: (this.galleries[gallery[0]][gallery[1]].length)/this.imageCount};
											
						if (!this.galleries[gallery[0]][gallery[1]][i+this.imageCount]) {
							$('lightwindow_next').setStyle({
								display: 'none'
							});
						} else {
							$('lightwindow_next').setStyle({
								display: 'block'
							});
							$('lightwindow_next_title').innerHTML = this.galleries[gallery[0]][gallery[1]][i+this.imageCount].title;
						}
						
						if (!this.galleries[gallery[0]][gallery[1]][i-this.imageCount]) {
							$('lightwindow_previous').setStyle({
								display: 'none'
							});
						} else {
							$('lightwindow_previous').setStyle({
								display: 'block'
							});
							$('lightwindow_previous_title').innerHTML = this.galleries[gallery[0]][gallery[1]][i-this.imageCount].title;
						}
					}

					images[i] = document.createElement('img');
					images[i].setAttribute('id', 'lightwindow_image_'+i);
					images[i].setAttribute('border', '0');
					images[i].setAttribute('src', this.contentToFetch);
					$('lightwindow_contents').appendChild(images[i]);

					// We have to do this instead of .onload 
					this.checkImage[i] = new PeriodicalExecuter(function(i) {
						if (!(typeof $('lightwindow_image_'+i).naturalWidth != "undefined" && $('lightwindow_image_'+i).naturalWidth == 0)) {
	
							this.checkImage[i].stop();
	
							var imageHeight = $('lightwindow_image_'+i).getHeight();
							if (imageHeight > this.resizeTo.height) {
								this.resizeTo.height = imageHeight;
							}
							this.resizeTo.width += $('lightwindow_image_'+i).getWidth();
							this.imageCount--;
	
							$('lightwindow_image_'+i).setStyle({
								height: '100%'
							});
	
						 	if (this.imageCount == 0) {
								this._processWindow();
						 	}
						}
					
					}.bind(this, i), 1);			
				}


			break;
		
		case 'media' :			
		
			var current = 0;
			this.resizeTo.height = this.resizeTo.width = 0;

			// If there is a gallery get it
			if (gallery = this._getGalleryInfo(this.element.rel)) {	
				for (current = 0; current < this.galleries[gallery[0]][gallery[1]].length; current++) {
					if (this.contentToFetch.indexOf(this.galleries[gallery[0]][gallery[1]][current].href) > -1) {
						break;
					}
				}
				
				if (this.galleries[gallery[0]][gallery[1]][current-1]) {
					this.navigationObservers.previous = this.galleries[gallery[0]][gallery[1]][current-1];
				} else {
					this.navigationObservers.previous = false;
				}
				if (this.galleries[gallery[0]][gallery[1]][current+1]) {
					this.navigationObservers.next = this.galleries[gallery[0]][gallery[1]][current+1];
				} else {
					this.navigationObservers.next = false;
				}
		
				this.activeGallery = true;
			} else {
				this.navigationObservers.previous = false;
				this.navigationObservers.next = false;
				
				this.activeGallery = false;
			}
		

			if (gallery && this.galleries[gallery[0]][gallery[1]][current]) {
				this.contentToFetch = this.galleries[gallery[0]][gallery[1]][current].href;

				this.galleryLocation = {current: current+1, total: this.galleries[gallery[0]][gallery[1]].length};
				
				if (!this.galleries[gallery[0]][gallery[1]][current+1]) {
					$('lightwindow_next').setStyle({
						display: 'none'
					});
				} else {
					$('lightwindow_next').setStyle({
						display: 'block'
					});
					$('lightwindow_next_title').innerHTML = this.galleries[gallery[0]][gallery[1]][current+1].title;
				}
				
				if (!this.galleries[gallery[0]][gallery[1]][current-1]) {
					$('lightwindow_previous').setStyle({
						display: 'none'
					});
				} else {
					$('lightwindow_previous').setStyle({
						display: 'block'
					});
					$('lightwindow_previous_title').innerHTML = this.galleries[gallery[0]][gallery[1]][current-1].title;
				}
			}
			
			if (this._getParameter('lightwindow_iframe_embed')) {
				this.resizeTo.height = this.dimensions.viewport.height;
				this.resizeTo.width = this.dimensions.viewport.width;	
			} else {
				this.resizeTo.height = this._getParameter('lightwindow_height');
				this.resizeTo.width = this._getParameter('lightwindow_width');				
			}
			
			this._processWindow();
			
			break;

		case 'external' :		

			this._appendIframe('auto');

			this.resizeTo.height = this.dimensions.viewport.height;
			this.resizeTo.width = this.dimensions.viewport.width;
						
			this._processWindow();

			break;
				
		case 'page' :	
			
			var newAJAX = new Ajax.Request(
				this.contentToFetch, {
					method: 'get', 
					parameters: '', 
					onComplete: function(response) {
						$('lightwindow_contents').innerHTML += response.responseText;
						this.resizeTo.height = $('lightwindow_contents').scrollHeight+(this.options.contentOffset.height);
						this.resizeTo.width = $('lightwindow_contents').scrollWidth+(this.options.contentOffset.width);
						this._processWindow();
					}.bind(this)
				}
			);
			
			break;
			
		case 'inline' : 
		
			var content = this.contentToFetch;
			if (content.indexOf('?') > -1) {
				content = content.substring(0, content.indexOf('?'));
			}
			content = content.substring(content.indexOf('#')+1);
			
			new Insertion.Top($('lightwindow_contents'), $(content).innerHTML);
			
			this.resizeTo.height = $('lightwindow_contents').scrollHeight+(this.options.contentOffset.height);
			this.resizeTo.width = $('lightwindow_contents').scrollWidth+(this.options.contentOffset.width);
			
			this._toggleTroubleElements('hidden', true); 			
			this._processWindow();
			
			break;
			
		default : 
			throw("Page Type could not be determined, please amend this lightwindow URL "+this.contentToFetch);
			break;
		}
	},
	//
	//  Resize the Window to fit the viewport if necessary
	//
	_resizeWindowToFit : function() {
		if (this.resizeTo.height+this.dimensions.cruft.height > this.dimensions.viewport.height) {
			var heightRatio = this.resizeTo.height/this.resizeTo.width;
			this.resizeTo.height = this.dimensions.viewport.height-this.dimensions.cruft.height-(2*this.options.viewportPadding);
			// We only care about ratio's with this window type			
			if (this.windowType == 'image' || (this.windowType == 'media' && !this._getParameter('lightwindow_iframe_embed'))) {
				this.resizeTo.width = this.resizeTo.height/heightRatio;
				$('lightwindow_data_slide_inner').setStyle({
					width: this.resizeTo.width+'px'
				});			
			}
		} 
		if (this.resizeTo.width+this.dimensions.cruft.width > this.dimensions.viewport.width) {
			var widthRatio = this.resizeTo.width/this.resizeTo.height;
			this.resizeTo.width = this.dimensions.viewport.width-2*this.dimensions.cruft.width-(2*this.options.viewportPadding);
			// We only care about ratio's with this window type
			if (this.windowType == 'image' || (this.windowType == 'media' && !this._getParameter('lightwindow_iframe_embed'))) {
				this.resizeTo.height = this.resizeTo.width/widthRatio;
				$('lightwindow_data_slide_inner').setStyle({
					height: this.resizeTo.height+'px'
				});
			}
		}
			
	},
	//
	//  Set the Window to a preset size
	//
	_presetWindowSize : function() {
		if (this._getParameter('lightwindow_height')) {
			this.resizeTo.height = parseFloat(this._getParameter('lightwindow_height'));
		}
		if (this._getParameter('lightwindow_width')) {
			this.resizeTo.width = parseFloat(this._getParameter('lightwindow_width'));
		}
	},
	//
	//  Process the Window
	//
	_processWindow : function() {
		// Clean out our effects
		this.dimensions.dataEffects = [];

		// Set up the data-slide if we have caption information
		if (this.element.caption || this.element.author || (this.activeGallery && this.options.showGalleryCount)) {
			if (this.element.caption) {
				$('lightwindow_data_caption').innerHTML = this.element.caption;
				$('lightwindow_data_caption').setStyle({
					display: 'block'
				});
			} else {
				$('lightwindow_data_caption').setStyle({
					display: 'none'
				});				
			}
			if (this.element.author) {
				$('lightwindow_data_author').innerHTML = this.element.author;
				$('lightwindow_data_author_container').setStyle({
					display: 'block'
				});
			} else {
				$('lightwindow_data_author_container').setStyle({
					display: 'none'
				});				
			}
			if (this.activeGallery && this.options.showGalleryCount) {
				$('lightwindow_data_gallery_current').innerHTML = this.galleryLocation.current;
				$('lightwindow_data_gallery_total').innerHTML = this.galleryLocation.total;
				$('lightwindow_data_gallery_container').setStyle({
					display: 'block'
				});
			} else {
				$('lightwindow_data_gallery_container').setStyle({
					display: 'none'
				});				
			}

			$('lightwindow_data_slide_inner').setStyle({
				width: this.resizeTo.width+'px',
				height: 'auto',
				visibility: 'visible',
				display: 'block'
			});
			$('lightwindow_data_slide').setStyle({
				height: $('lightwindow_data_slide').getHeight()+'px',
				width: '1px',
				overflow: 'hidden',
				display: 'block'
			});
		} else {
			$('lightwindow_data_slide').setStyle({
				display: 'none',
				width: 'auto'
			});
			$('lightwindow_data_slide_inner').setStyle({
				display: 'none',
				visibility: 'hidden',
				width: this.resizeTo.width+'px',
				height: '0px'
			});
		}
				
		if (this.element.title != 'null') {		
			$('lightwindow_title_bar_title').innerHTML = this.element.title;
		} else {
			$('lightwindow_title_bar_title').innerHTML = '';
		}
		
		var originalContainerDimensions = {height: $('lightwindow_container').getHeight(), width: $('lightwindow_container').getWidth()};
		// Position the window
    	$('lightwindow_container').setStyle({
			height: 'auto',
			// We need to set the width to a px not auto as opera has problems with it
			width: $('lightwindow_container').getWidth()+this.options.contentOffset.width-(this.windowActive ? this.options.contentOffset.width : 0)+'px'
		});
		var newContainerDimensions = {height: $('lightwindow_container').getHeight(), width: $('lightwindow_container').getWidth()};
 		
		// We need to record the container dimension changes
		this.containerChange = {height: originalContainerDimensions.height-newContainerDimensions.height, width: originalContainerDimensions.width-newContainerDimensions.width};

		// Get out general dimensions
		this.dimensions.container = {height: $('lightwindow_container').getHeight(), width: $('lightwindow_container').getWidth()};
		this.dimensions.cruft = {height: this.dimensions.container.height-$('lightwindow_contents').getHeight()+this.options.contentOffset.height, width: this.dimensions.container.width-$('lightwindow_contents').getWidth()+this.options.contentOffset.width};
		
		// Set Sizes if we need too
		this._presetWindowSize();
		this._resizeWindowToFit(); // Even if the window is preset we still don't want it to go outside of the viewport

		if (!this.windowActive) {
			// Position the window
		   	$('lightwindow_container').setStyle({
				left: -(this.dimensions.container.width/2)+'px',
				top: -(this.dimensions.container.height/2)+'px'
			});
		}
	   	$('lightwindow_container').setStyle({
			height: this.dimensions.container.height+'px',
			width: this.dimensions.container.width+'px'
		});
		
		// We are ready, lets show this puppy off!
		this._displayLightWindow('block', 'visible');
		this._animateLightWindow();
	},
	//
	//  Fire off our animation handler
	//
	_animateLightWindow : function() {
		if (this.options.animationHandler) {
			this.options.animationHandler().bind(this);
		} else {
			this._defaultAnimationHandler();
		}
	},
	//
	//  Fire off our transition handler
	//
	_handleNavigation : function(display) {
		if (this.options.navigationHandler) {
			this.options.navigationHandler().bind(this, display);
		} else {
			this._defaultDisplayNavigation(display);
		}
	},
	//
	//  Fire off our transition handler
	//
	_handleTransition : function() {
		if (this.options.transitionHandler) {
			this.options.transitionHandler().bind(this);
		} else {
			this._defaultTransitionHandler();
		}
	},
	//
	//  Handle the finish of the window animation
	// 
	_handleFinalWindowAnimation : function(delay) {
		if (this.options.finalAnimationHandler) {
			this.options.finalAnimationHandler().bind(this, delay);
		} else {
			this._defaultfinalWindowAnimationHandler(delay);
		}		
	},
	//
	//  Handle the gallery Animation
	// 
	_handleGalleryAnimation : function(list) {
		if (this.options.galleryAnimationHandler) {
			this.options.galleryAnimationHandler().bind(this, list);
		} else {
			this._defaultGalleryAnimationHandler(list);
		}		
	},
	//
	//  Display the navigation 
	//
	_defaultDisplayNavigation : function(display) {
		if (display) {
			$('lightwindow_navigation').setStyle({
				display: 'block',
				height: $('lightwindow_contents').getHeight()+'px',
				width: '100%',
				marginTop: this.options.dimensions.titleHeight+'px'
			});			
		} else {
			$('lightwindow_navigation').setStyle({
				display: 'none',
				height: 'auto',
				width: 'auto'
			});			
		}
	},
	//
	//  This is the default animation handler for LightWindow
	//
	_defaultAnimationHandler : function() {	
		// Now that we have figures out the cruft lets make the caption go away and add its effects
		if (this.element.caption || this.element.author || (this.activeGallery && this.options.showGalleryCount)) {
			$('lightwindow_data_slide').setStyle({
				display: 'none',
				width: 'auto'
			});
			this.dimensions.dataEffects.push(
				new Effect.SlideDown('lightwindow_data_slide', {sync: true}),
				new Effect.Appear('lightwindow_data_slide', {sync: true, from: 0.0, to: 1.0})
			);
		}

		// Set up the Title if we have one
		$('lightwindow_title_bar_inner').setStyle({
			height: '0px',
			marginTop: this.options.dimensions.titleHeight+'px'
		});
		
		// We always want the title bar as well
		this.dimensions.dataEffects.push(
			new Effect.Morph('lightwindow_title_bar_inner', {sync: true, style: {height: this.options.dimensions.titleHeight+'px', marginTop: '0px'}}),
		 	new Effect.Appear('lightwindow_title_bar_inner', {sync: true, from: 0.0, to: 1.0})
		);		
		
		if (!this.options.hideGalleryTab) {
			this._handleGalleryAnimation(false);
			if ($('lightwindow_galleries_tab_container').getHeight() == 0) {
				this.dimensions.dataEffects.push(
					new Effect.Morph('lightwindow_galleries_tab_container', {sync: true, style: {height: '20px', marginTop: '0px'}})
				);
				$('lightwindow_galleries').setStyle({
					width: '0px'
				});
			}
		}
		
		var resized = false;
		var ratio = this.dimensions.container.width-$('lightwindow_contents').getWidth()+this.resizeTo.width+this.options.contentOffset.width;
		if (ratio != $('lightwindow_container').getWidth()) {
			new Effect.Parallel([
					new Effect.Scale('lightwindow_contents', 100*(this.resizeTo.width/$('lightwindow_contents').getWidth()), {scaleFrom: 100*($('lightwindow_contents').getWidth()/($('lightwindow_contents').getWidth()+(this.options.contentOffset.width))), sync: true,  scaleY: false, scaleContent: false}),
					new Effect.Scale('lightwindow_container', 100*(ratio/(this.dimensions.container.width)), {sync: true, scaleY: false, scaleFromCenter: true, scaleContent: false})
				], {
					duration: this.duration, 
					delay: 0.25,
					queue: {position: 'end', scope: 'lightwindowAnimation'}
				}
			);		
		}
		
		ratio = this.dimensions.container.height-$('lightwindow_contents').getHeight()+this.resizeTo.height+this.options.contentOffset.height;
		if (ratio != $('lightwindow_container').getHeight()) {
			new Effect.Parallel([
					new Effect.Scale('lightwindow_contents', 100*(this.resizeTo.height/$('lightwindow_contents').getHeight()), {scaleFrom: 100*($('lightwindow_contents').getHeight()/($('lightwindow_contents').getHeight()+(this.options.contentOffset.height))), sync: true, scaleX: false, scaleContent: false}),
					new Effect.Scale('lightwindow_container', 100*(ratio/(this.dimensions.container.height)), {sync: true, scaleX: false, scaleFromCenter: true, scaleContent: false})
				], {
					duration: this.duration, 
					afterFinish: function() {				
						if (this.dimensions.dataEffects.length > 0) {
							if (!this.options.hideGalleryTab) {
								$('lightwindow_galleries').setStyle({
									width: this.resizeTo.width+'px'
								});
							}
							new Effect.Parallel(this.dimensions.dataEffects, {
									duration: this.duration,
									afterFinish: function() {
										this._finishWindow();
									}.bind(this),
									queue: {position: 'end', scope: 'lightwindowAnimation'} 
								}
							);
						}
					}.bind(this), 
					queue: {position: 'end', scope: 'lightwindowAnimation'} 
				}
			);
			resized = true;
		}
		
		// We need to do our data effect since there was no resizing
		if (!resized && this.dimensions.dataEffects.length > 0) {	
			new Effect.Parallel(this.dimensions.dataEffects, {
					duration: this.duration,
					beforeStart: function() {
						if (!this.options.hideGalleryTab) {
							$('lightwindow_galleries').setStyle({
								width: this.resizeTo.width+'px'
							});
						}
						if (this.containerChange.height != 0 || this.containerChange.width != 0) {
							new Effect.MoveBy('lightwindow_container', this.containerChange.height, this.containerChange.width, {transition: Effect.Transitions.sinoidal});
						}
					}.bind(this),			
					afterFinish: function() {
						this._finishWindow();
					}.bind(this),
					queue: {position: 'end', scope: 'lightwindowAnimation'} 
				}
			);
		}			
		
	},
	//
	//  Finish up Window Animation
	//
	_defaultfinalWindowAnimationHandler : function(delay) {
		if (this.windowType == 'media' || this._getParameter('lightwindow_loading_animation')) {	
			// Because of major flickering with the overlay we just hide it in this case
			Element.hide('lightwindow_loading');
			this._handleNavigation(this.activeGallery);
			this._setStatus(false);
		} else {
			Effect.Fade('lightwindow_loading', {
				duration: 0.75,
				delay: 1.0, 
				afterFinish: function() {
					// Just in case we need some scroll goodness (this also avoids the swiss cheese effect)
					if (this.windowType != 'image' && this.windowType != 'media' && this.windowType != 'external') {
						$('lightwindow_contents').setStyle({
							overflow: 'auto'
						});
					}
					this._handleNavigation(this.activeGallery);
					this._defaultGalleryAnimationHandler();
					this._setStatus(false);
				}.bind(this),
				queue: {position: 'end', scope: 'lightwindowAnimation'}
			});
		}
	},
	//
	//  Handle the gallery Animation
	//
	_defaultGalleryAnimationHandler : function(list) {
		if (this.activeGallery) {
			$('lightwindow_galleries').setStyle({
				display: 'block',
				marginBottom: $('lightwindow_data_slide').getHeight()+this.options.contentOffset.height/2+'px'
			});
			$('lightwindow_navigation').setStyle({
				height: $('lightwindow_contents').getHeight()-20+'px'
			});
		} else {
			$('lightwindow_galleries').setStyle({
				display: 'none'
			});	
			$('lightwindow_galleries_tab_container').setStyle({
				height: '0px',
				marginTop: '20px'
			});
			$('lightwindow_galleries_list').setStyle({
				height: '0px'
			});
			return false;
		}
		
		if (list) {
			if ($('lightwindow_galleries_list').getHeight() == 0) {
				var height = $('lightwindow_contents').getHeight()*0.80;
				$('lightwindow_galleries_tab_span').className = 'down';
			} else {
				var height = 0;
				$('lightwindow_galleries_tab_span').className = 'up';
			}

			new Effect.Morph('lightwindow_galleries_list', {
				duration: this.duration,
				transition: Effect.Transitions.sinoidal,
				style: {height: height+'px'},
				beforeStart: function() {
					$('lightwindow_galleries_list').setStyle({
						overflow: 'hidden'
					});					
				},
				afterFinish: function() {
					$('lightwindow_galleries_list').setStyle({
						overflow: 'auto'
					});
				},
				queue: {position: 'end', scope: 'lightwindowAnimation'}
			});	
		}
		
		
	},
	//
	//  Default Transition Handler
	//
	_defaultTransitionHandler : function() {
		// Clean out our effects
		this.dimensions.dataEffects = [];

		// Now that we have figures out the cruft lets make the caption go away and add its effects
		if ($('lightwindow_data_slide').getStyle('display') != 'none') {
			this.dimensions.dataEffects.push(
				new Effect.SlideUp('lightwindow_data_slide', {sync: true}),
				new Effect.Fade('lightwindow_data_slide', {sync: true, from: 1.0, to: 0.0})
			);
		}
		
		if (!this.options.hideGalleryTab) {
			if ($('lightwindow_galleries').getHeight() != 0 && !this.options.hideGalleryTab) {
				this.dimensions.dataEffects.push(
					new Effect.Morph('lightwindow_galleries_tab_container', {sync: true, style: {height: '0px', marginTop: '20px'}})
				);
			}
			
			if ($('lightwindow_galleries_list').getHeight() != 0) {
				$('lightwindow_galleries_tab_span').className = 'up';
				this.dimensions.dataEffects.push(
					new Effect.Morph('lightwindow_galleries_list', {
						sync: true, 
						style: {height: '0px'},
						transition: Effect.Transitions.sinoidal,
						beforeStart: function() {
							$('lightwindow_galleries_list').setStyle({
								overflow: 'hidden'
							});					
						},
						afterFinish: function() {
							$('lightwindow_galleries_list').setStyle({
								overflow: 'auto'
							});
						}
					})
				);
			}
		}
		
		// We always want the title bar as well
		this.dimensions.dataEffects.push(
			new Effect.Morph('lightwindow_title_bar_inner', {sync: true, style: {height: '0px', marginTop: this.options.dimensions.titleHeight+'px'}}),
		 	new Effect.Fade('lightwindow_title_bar_inner', {sync: true, from: 1.0, to: 0.0})
		);

		new Effect.Parallel(this.dimensions.dataEffects, {
				duration: this.duration,
				afterFinish: function() {
					this._loadWindow();
				}.bind(this),
				queue: {position: 'end', scope: 'lightwindowAnimation'} 
			}
		);	
	},
	//
	//	Default Form handler for LightWindow
	//
	_defaultFormHandler : function(e) {
		var element = Event.element(e).parentNode;
		var parameterString = Form.serialize(this._getParameter('lightwindow_form', element.getAttribute('params')));
		if (this.options.formMethod == 'post') {
			var newAJAX = new Ajax.Request(element.href, { 
				method: 'post', 
				postBody: parameterString, 
				onComplete: this.openWindow.bind(this, element)
			});
		} else if (this.options.formMethod == 'get') {
			var newAJAX = new Ajax.Request(element.href, { 
				method: 'get', 
				parameters: parameterString, 
				onComplete: this.openWindow.bind(this, element)
			});
		}
	},
	// 
	//  Wrap everything up
	//
	_finishWindow : function() {
		if (this.windowType == 'external') {
			// We set the externals source here because it allows for a much smoother animation
			$('lightwindow_iframe').setAttribute('src', this.element.href);
			this._handleFinalWindowAnimation(1);	
		} else if (this.windowType == 'media') {

			var outerObject = document.createElement('object');
			outerObject.setAttribute('classid', this.options.classids[this._fileExtension(this.contentToFetch)]);
			outerObject.setAttribute('codebase', this.options.codebases[this._fileExtension(this.contentToFetch)]);
			outerObject.setAttribute('id', 'lightwindow_media_primary');
			outerObject.setAttribute('name', 'lightwindow_media_primary');
			outerObject.setAttribute('width', this.resizeTo.width);
			outerObject.setAttribute('height', this.resizeTo.height);
			outerObject = this._addParamToObject('movie', this.contentToFetch, outerObject);
			outerObject = this._addParamToObject('src', this.contentToFetch, outerObject);
			outerObject = this._addParamToObject('controller', 'true', outerObject);
			outerObject = this._addParamToObject('wmode', 'transparent', outerObject);
			outerObject = this._addParamToObject('cache', 'false', outerObject);
			outerObject = this._addParamToObject('quality', 'high', outerObject);

			if (!Prototype.Browser.IE) {
				var innerObject = document.createElement('object');
				innerObject.setAttribute('type', this.options.mimeTypes[this._fileExtension(this.contentToFetch)]);
				innerObject.setAttribute('data', this.contentToFetch);
				innerObject.setAttribute('id', 'lightwindow_media_secondary');
				innerObject.setAttribute('name', 'lightwindow_media_secondary');
				innerObject.setAttribute('width', this.resizeTo.width);
				innerObject.setAttribute('height', this.resizeTo.height);
				innerObject = this._addParamToObject('controller', 'true', innerObject);
				innerObject = this._addParamToObject('wmode', 'transparent', innerObject);
				innerObject = this._addParamToObject('cache', 'false', innerObject);
				innerObject = this._addParamToObject('quality', 'high', innerObject);
			
				outerObject.appendChild(innerObject);
			}	
			
			if (this._getParameter('lightwindow_iframe_embed')) {
				this._appendIframe('no');
				this._writeToIframe(this._convertToMarkup(outerObject, 'object'));
			} else {
				this._appendObject(outerObject, 'object', $('lightwindow_contents'));
			}

			this._handleFinalWindowAnimation(0);
		} else {
			this._handleFinalWindowAnimation(0);
		}

		// Initialize any actions
		this._setupActions();
	}
}

/*-----------------------------------------------------------------------------------------------*/

Event.observe(window, 'load', lightwindowInit, false);

//
//	Set up all of our links
//
var myLightWindow = null;
function lightwindowInit() {
	myLightWindow = new lightwindow();
}