From b0423691d9a44eae86799ad242c4fea58f9acd8d Mon Sep 17 00:00:00 2001 From: pvtroshin Date: Fri, 8 Apr 2011 12:35:44 +0000 Subject: [PATCH] Adding new website from r3934 JABA_r1 branch git-svn-id: link to svn.lifesci.dundee.ac.uk/svn/barton/ptroshin/JABA2@3936 e3abac25-378b-4346-85de-24260fe3988d --- website/Example_template.pdf | Bin 0 -> 56257 bytes website/contacts.html | 74 + website/develhome.html | 128 + website/download.html | 124 + website/images/VMware_booted.png | Bin 0 -> 9498 bytes website/images/VMware_copy_q.png | Bin 0 -> 9230 bytes website/images/VMware_cpu.png | Bin 0 -> 33013 bytes website/images/align.png | Bin 0 -> 3403 bytes website/images/banner_bg.gif | Bin 0 -> 767 bytes website/images/banner_bg1.gif | Bin 0 -> 800 bytes website/images/brickhead2.jpg | Bin 0 -> 10942 bytes website/images/brickhead2_line.jpg | Bin 0 -> 10969 bytes website/images/dir.gif | Bin 0 -> 349 bytes website/images/jabaws.png | Bin 0 -> 9622 bytes website/images/matrix_bg6.jpg | Bin 0 -> 6315 bytes website/images/minus.png | Bin 0 -> 933 bytes website/images/mm_spacer.gif | Bin 0 -> 43 bytes website/images/panel_bg.gif | Bin 0 -> 1901 bytes website/images/panel_bg.jpg | Bin 0 -> 397 bytes website/images/panel_bg_long.gif | Bin 0 -> 1927 bytes website/images/plus.png | Bin 0 -> 211 bytes website/images/uod.gif | Bin 0 -> 1542 bytes website/images/uod_h.gif | Bin 0 -> 2534 bytes website/images/uod_lt.gif | Bin 0 -> 2803 bytes website/images/vm_welcome_screen.png | Bin 0 -> 9481 bytes website/images/vmb_virtual.png | Bin 0 -> 21851 bytes website/images/ws-structure.png | Bin 0 -> 19953 bytes website/index.html | 128 + website/man_about.html | 122 + website/man_client.html | 111 + website/man_configuration.html | 437 ++++ website/man_dev.html | 359 +++ website/man_servervm.html | 177 ++ website/man_serverwar.html | 265 +++ website/manual_qs_client.html | 98 + website/manual_qs_va.html | 102 + website/manual_qs_war.html | 116 + website/print.css | 188 ++ website/prototype-1.6.0.3.js | 4320 ++++++++++++++++++++++++++++++++++ website/quick_start.html | 80 + website/ws.css | 379 +++ 41 files changed, 7208 insertions(+) create mode 100644 website/Example_template.pdf create mode 100644 website/contacts.html create mode 100644 website/develhome.html create mode 100644 website/download.html create mode 100644 website/images/VMware_booted.png create mode 100644 website/images/VMware_copy_q.png create mode 100644 website/images/VMware_cpu.png create mode 100644 website/images/align.png create mode 100644 website/images/banner_bg.gif create mode 100644 website/images/banner_bg1.gif create mode 100644 website/images/brickhead2.jpg create mode 100644 website/images/brickhead2_line.jpg create mode 100644 website/images/dir.gif create mode 100644 website/images/jabaws.png create mode 100644 website/images/matrix_bg6.jpg create mode 100644 website/images/minus.png create mode 100644 website/images/mm_spacer.gif create mode 100644 website/images/panel_bg.gif create mode 100644 website/images/panel_bg.jpg create mode 100644 website/images/panel_bg_long.gif create mode 100644 website/images/plus.png create mode 100644 website/images/uod.gif create mode 100644 website/images/uod_h.gif create mode 100644 website/images/uod_lt.gif create mode 100644 website/images/vm_welcome_screen.png create mode 100644 website/images/vmb_virtual.png create mode 100644 website/images/ws-structure.png create mode 100644 website/index.html create mode 100644 website/man_about.html create mode 100644 website/man_client.html create mode 100644 website/man_configuration.html create mode 100644 website/man_dev.html create mode 100644 website/man_servervm.html create mode 100644 website/man_serverwar.html create mode 100644 website/manual_qs_client.html create mode 100644 website/manual_qs_va.html create mode 100644 website/manual_qs_war.html create mode 100644 website/print.css create mode 100644 website/prototype-1.6.0.3.js create mode 100644 website/quick_start.html create mode 100644 website/ws.css diff --git a/website/Example_template.pdf b/website/Example_template.pdf new file mode 100644 index 0000000000000000000000000000000000000000..20dc74fe1dff7ee2ad8303ea6871aea7624e3bb4 GIT binary patch literal 56257 zcmdSC30zZG^8i{`up$seQ4oQ+SJ`*jssy!lL8P@P0swZGR!a`@ax1XomDerL4qZ)cTyETlA^^Ht)>@@WB zbZj*Y^^8sQb@poL>wE)#&^6H0*{R{AVPascp|7XsY-P2`)9)zgW|4;UzeS&ip7J~f zJxO1G(dW9Ne|p9m@Rf$&M46ePiDa3cuD+pEnZB;6RGERHu2h++zEnMZU1NYS^l$RH z`UXZ)ZS@UIrJk#AtS1GZzNwKE9tHqt$!8eonMlE6YGfq&3_Sx~GpRBYJu}I+`g%rE z`05)O8Av`?-^|p+NCFlE15;y3JPgcqbqyry>FPqGJ3*_UQ*Pcqo~IUl4j9D&@Q4Or zfqkbuLm+O@*VEaL#Rh5U0Xk~z*ZIot7*+#-3|(TJEKE!dwi#_Tven;)F*ev{V7yh| z*u=oZ$ZWf@nURT^p`n$9f#Eh&J$=)ywtCz2F@}c5TWt)s8g8@MYM^hl)x<#0%nD+# z&jW+pP6Z*Xq`T1_9L z3-ZKxdSH)w>U^c4XQ&U@TuKhZ?off9`MW;``ae4eED`O7bnRuxD4f`i=MYYXxayjy|yw_eWrt7nY`$8Fq1@(h~^YbRs^Lzo%R>f>I6~D$jnGvUth!2P~RCeKIQ2b zBlXy>0-f}shWo)BMoxfTpgXvC4Sm35&>akkhCU3O1~mIL_B#XC2m(~s(AC-F zdDPo&rU&l#48#VX@&Ksl!M!86K*&vj8~Ozyf(_OOd& zU_se8-{@=T!2p6wLom+J&)^c&gaHLL_npFeICus*=>T!4^NnX{kh6|$XwVJ^2vpF+ z4hKCAeVCiAz(28YgZo5aa0qq}f(ZW2sbEi-^3bC(o`D{xy#0f)r!*i@0iL3CbOSk_qxSuCo_=%Gb>Y zuKJy)x7YC?4MSaBNI`i8Y8V*mK%xW^!deDUDQLG15}aB<2x}Re0%94M0&T0W=d808 zsb>mU9ICe6&DYx}Y=h{*8el4H1WLhwC-Mj*6H^^W(X|$IGr|0mqDu#%+Eza=A0V`+ zObUq8ry{B+f=mk233mKTbWQ#Sx`xIYS|&jKnE;DQPye5zYi2M7U1MOoLLwU?)89Z> zWEcZw-~f-Sftj`$FokCvTdhe>`%9cBhuF;Y&xRNnXIlCuh8m_|Rsa%%Isd;MVl6$R z$w7v79x}*w`}TlkfZaZgV{Sfyo;p~6(FIJy30YRkOR|<=-S=NcUlP<6JPF-oPIroP>7q`y; z>R3yoPw~4{)~~%u+AQL4eZC(%(+|g6ti!)}X_ouIaJ(S1yw58qN+;X!1M8Ug;`QjS z2XI5F`@A=6KKuHYukYN#r>|{}d!@R0-Nq-XKk;?$Ui^rsq-3f4b*E5-<$?;K=_c+9 zd8_B>X9rj9TJdHZS>w84av&<#&kIKld($6Qr#cHudm0vAbfCFm%h&GSN4K~v_Y$l> zM7L;7Mk!3E(nHR|aKZ3ceIUE+L3uRK z+#n-?^SjrDnt0mtzyw$0SM@_o9bq()6xJTdQ0A;@bGer>Iufv?Os%N+qVtxLFrrI7 zDPs@0_EGA*Ha|wl#@evPEi2n!f36gL;)jC?S-&0FzoY%tJZ*}dY0D0tYj(D)zgo8E za1(xQbCY99$}#WE&L599Ul(rL%O5`~=yrRt?R-u0qi-CC|A^AM(?yhd+zwdp>;d=JSn)cY5zBh%ijO8Zn+U% z`{RKdUu^zd!*)f>sjVjxmflC(%J%MFTBCbF$pbzty{l5`sF$>~#?c_js1iEBS2d1x zKKs7c(@i?#E+^-qv3yST@(r~Qb>}A(UR!FTXDsIdAC^2nL@2zrJWbK#l46oQp}^QJ z3H@;S2u3F1GmjTRe|+ZQb9+hchS^E>cFVcTR<^85vfpqZU3WX`$nBd{3_zTR-4ifZEY(0UL&V@?0SI*DSJ)losJ`$q`b^GHB(BGy*a=P0s z-EN;c^mu{j0oP@9x9>TLG>lokDWULlJu!{|Q9U(7vZF(iQ8hRO6AEuGKN$-j1`XGU zaQtPt&C?TeJ&r7&Q`4%Ow5Sp~z*jY`WS>74cx1%D(4dYa9s2RmX}uG+iSV<6zuvU5 za=Gnk2$_u7<=1cC2Qb1&-`7}vUD3_AO7tUy>HA-1)oxk690JwSEoocqeL#SOr2zlA z%X_@7R=6h}`okUWN$IwTlre>kHc9pi_b=3KF%v&V35-mkJA@)QOkO1v-dwszuSL!S zKBz%M1EHz6FG-Uu8ayzbnm5nJE>}$`bb}5H^o*4}s&&C(iM!n6UGp5tb5sUT+gkjB zQm7)x7&2xhhJLwvRRKX}&E%yaW9#z4)7veMpcIai=PVmMjhVdM4z)x|;R-w93ZlAa zbs4jgLm#47{Xvk~%$OBFd6^ul2)7hJ{>m5NcX3s>NtnRzi$&nURW*`C;31HrAxOnQ zgNKMOr@`-aoNVAmHZWwYST-n^92#qDVS~i^NWt7Kic>ua@KY-SOqyYvS#e*G6;4Y=@Do78@J??Fa; zL&xY{CE@Dqxp))2uV2;K)HMfRSU3LouDW;4cpq2LeVhEdeb>!f4eQ>zKaFvZEFZr< zDVJD|KCmZGvFA zcCUipluFG>qXq}Dy_Y&$)9|6;Wl`bB{EXdBVof|wnLcXRn5N54d7d$pF={E;^nn%9 znBIM7ZRFd&r0BiEyFUl=Bl(f|?wlG_%`psVgfrXchu3R9EPTOV^ni*;!$JQQtsR2- zzF~9u8aTEcMS@RZE~|s&T8G7VMR}@B{X=P~ny#J5qx5MSRPkvRqT6C&K>%$5A)R2PQ z-w*j&sb(2*)0+G*yu9!>ZuAcJYKYsep!4)!3Z312owF+gd$gVJ7vydBdC6Hg!2A!k zFFPPlyMFvbS@9whomzGizhR-!IQT{wQ(K!_6zo;wdD2;r*l2u~KAZZDjc44QOlnEb zA9yd{SEdoioQCPGfhS9^<*J!voyPid)9QBJGksQ;%MCeRiu<;&?b=m^c3Y$T-t7KO z%<;+xVcyQqi}pAZkCpfbQgPqff8)#=FgN8bej4e=i7-wT;NdE{gIQR-+Xj0m}hl<;NZBt!u`AL?>d^e$IR~tf7+hXt?vHot=wSQf!R4^nH|*2 z&PGq`J?$F;zP2E6Hj@`nL+rb31|q#u9~%e{lnI}Gb@+pa9nEjfY#wz)AYX8IP2H+A zb-GJ_Na@Z?_;2ZS+YJcmm236;sS;qUkPWMWO3whH^SOX3UU0cSt{nw z`}-e0-E}dH6p@xXANQd(I`~Vkw)R!TFjKObG2wOV-M}wh+uBu$fyp{AWmcO1W>6;B zIV3auYkT>bv?fhsne+p{?JpCwvSaw%XZ;-y8+NJH&)NI?(}0}wmbr1mzh?Bsq&0nP zU0D?wYaZO|ZCP;XE6r}3mTx<)c)#Y#tv(?am;Re!T~CUy=g>=j-}9!P_PswEHp-i6 z#FKl3&w7dYpw~&BN6LE28@y^=Lwm1#XT4h<3r5H`n{l>ZRXglCpVhf|4px=AeV#(P0$LY|Za3bK2&ANaof_W8LU z;%}!NjeSb`>R4)D?d~6%FRL+c=dxMy=R?ibsE2cge9K-ln3hM&M(f!N`>XBP+sZ@D ziy|x8BL!FR!Zug`e3F87`@#`MN?~$pq${ZT6d&LcJV*lA1?jvWi32XTgS!r*{yFBmUA1@tUoSIZq$nApr6)fu!cvL^1DVuDjua#@%-2K8?qeg z-sr1yhD&&y@Y_t^K3;X7sW2k)TT+%nNpD^EUHtfX6N}YhSs_zg-2Hx_Zee?*%e(Ll zlP3Id{qF zFRW{zHqoQT-WKbGkB*gAKF`b&G*pwU@jO;)7Cs*9CkPR~>B+HEx3(@5j_SCw)cdW< zgwKT?<-%cq_MiaQv^9yZf6`R=bLp7BJk@HISLv7_AlHM-4ZS{ZE$GgNzifN4=+%L#O;&RSiit{h{% z!z_FezE=+4c#;!{;RG7{pakh>PsUg?jd*9`hjF;yPBGb&ed5Sj{rsh%+}QQ#sOy81dvZcpkfGy=htL~ zK^uz@cmUFX7}r;p$KqFt$dEOS40D=J0^mi+1ioE{U?_{P3IhF|r5f=d^ufac>Ob!= z;2q&;LPHd*E@!<4zG2?k1&!C&oW}!!7qzOuc&z|9odY=O#JVm9v; z=zlNL|9Za+VsItW|EG)VD#^JEkrs2r&)$nbIHh*D*JpouNg1TB6DX!6Nor)Wj87_3?1hrrNH zEB0j+%`4tRGY+7VeHZ$r5q&Ftb)dtNVl5*0EuOm0&&ePDP4&~ogJlz)%t6{q_WdWt z|Mrocqr}a`jA|8uSzcGx&|>&xP<)cZEQ`UPKgp?^N3^V~?9(eS>Ta9Uvmq}msN1J= zbS1kpT&bltSHZ`oWrd@%cCTXyxz9|YdR#Uyx8Sm`yiYx`f8-8<8n~);)mbNl+m^)h zRfo>^kN7Y~)7cNhl_;^f3VvsM10ovdIK`0W6f+3}H~{0DcSgJnq9ssn;OJGotc&%q z4~TCyqUFG`iOU@^qltd`N?KkQ3t*EEAAzcy>@gWAfQcSMTp^s1 zTHpx!M%t|gs(VgXT#QI36h3a2h1DC--;h2KHU*cb=_)?_Qqi|&>B`WichB)2#|#=` z6TfWU6+2+wY0}j_s3@4r)8sAS3=MqEvEeKkNQFNpojP6EhxEAoS*`>pyNAk*mZ7?y zb2_!TY;frNomHaeSFRHYA2j_eMOWbV+@{Wj0X+*i+i2mnJqulvoLKNdJ@2#*Id?ty zjk~Q#u{blVVxWdN@^c3}IV1Qi}LeMgC7iLlAzD z4nTm*_^-A9vKFv>Dqk(UdpoS)a$rCI zpa7Kq%r|rF^AE1$&0}tO`Z0)AOrp~TO+3DULmJxHcz$VDlUh1TK$BH>f(*Q~5SJ)? zhgc6sfyr=DYz#$m48_du4qHSp=jZ267DyQ@rnVr^uZjNuBP|_W(RzHd-dZeRD~4_jKsq@P9U0Bf*i*Tt8hES z_gg5SW6dGBCcVu{+%MGoL8Q8bX&3t1dj``kRAk!qG?U&wK`d4|(hArLg3UXHtnD1S zLRHq1uBP(ptmh^D15CM};r?09)Os<@0P>AJFkWnVp}8Es|12OVsE@RA$n5CC*NW?g zKt$j*1XZ5LF>5fI=d85-B-0B^Lg<28WFbX~ixo{wSjfnIe$RUx-*Ju)RS* zER??}KH2pz4G(GuWH>;Izo@h540Rb~TYL}92w+=$s#sZUYru8m#ck(*ve+}~-x?ke zkfH~X5u>NG1y7(xsNXi{MdS~#N~%fh&xM(gIE<%8kj{)LdDV@p&YE4! zwrG4c`>wKA-bQSyhhO9}|A?mPa(GTLJM!$%#;1)V=8iUR<({5X;I?e1b#P6OEo^kT z;@NQae!4*wSSTxkWv0lSNU=ypChg*AG+1ULl2u&+*bvCX9r5>s1uHfdtSwiFCNL|` zZZ%JtSiZgre})AIkeV~6;*(q zZ1v>%lwbNBQG$iEjwM~Bhq)vU4s^N-h&7#n2yC9LaGoD49_}ix2kr*x{r{~H!itxd zXPm4T76)qZY#_n#HBXE@+X(_5we6l?$)I zp#}AvPZwM4o&f7FR_*Kkoc-bDtY`_VOdGEfuS%DIbuCyhfA0iWdicp=*+-%!_V-RQ zNVo7hmLXnw|7o%7#HtypD*|bupW3uyVQSBVSINHU52jYgT3Dg{-8sJ$Y!=@iCZsC}DiHUruMp;$jDX^E1?q#0+wu5^XP|1^188 zno0!Ke}vZ*D!fTtCvG|&tv|tbqByF02D*b4|EJgQXRvF<%kxjW2BvBG>KSzI-+JWc zmtqhN{&p{npVyb+8R)@f>Re^-9Q zLVU)>o@Ih9HgC0fpn%(62vov@I1CQiBE@7wI(()pX+^-DY`*cl&1bb8wA9x^jKV*4BzT&b+39v>7Zd6T?+Z*_ZwLePvQzJWDQWh0c=5(n8 zP}u_tjF9%jK)2EImUO8^w$k#_Qnqts{7d)7;6E$wNk5F#j^M}y z^u+n90wly$LF+&Tp@tu&JPxl|+_MVk^@$GOG(!!3Y{StvO@pZ6fH>OK?X_6 z!kJciWdqHS6CYYdBz8?$Cgr}68y~v>SS7AUZGlgJPO%k%8ms^oGyp~nXAaRh$0A$- z0;8iELUH|p7;7+GXx=Q^_`~AaqB`rV)Xn`Ump=Ad^0v~(Kl7uQ5&OF!T10RF_9p7d z12EoD%e{GU8K8)UUlgYZCGMCFRcVCU=cz(VRaudfTc$cC(LzPMR>g=T6DzD%9fq9t z?wqw6J1_*abbg*whc<)>G|q6M7y zeNMF_^|+4qkeRS2HhQJSzuFSUrImJ;{ygIH#Qx6^mKs80s_DvR%~YdP;56-FQREicDXx2rB^ zl0Td=`g~Ism3!8;<8G7_IQaH#xV_}MLQ3OihLC?s~z3F@XTLhH|B zckx&=`EH=>@#(%BU67UeDc{Ymyfr3^G0kE5+cs(ZC>M(#eZf^PK6hgq_kP#8YqwsU z&D#39)Q=zh#etWuLcU$aCP7{j{tJcL2ae{oDm~wMBnRtS$#j=H(jTgvyTlreG^Jn# zHxHW^WLAaiRmgbwH#|HvWYX~6$-c3~6B&sk3vQ(EcZYo{B=nhs<>1MTAb=I5y&gEb1e=tqc(xB8S;B0HxDXYjuaxtG3|cy zPq2X3(9 z53tNK>pYsMvwBR zKM8}si2)tO`b7Bmey`mM{Zp_6znp@;I9FQn$0HM6gNxUtLlxW_7)gMSPA%xFa|_EU zo}1|~AV#N-L4eR3fUqEnv3ksHtic6{ky*%ghVf$o{48(26{FK%gF?__(G_F_BV87D zyq>Ub*QV9NaF;R4Xn6NnvW+lYhV4MpVX{F;*MO)TttJ?(tieZVv)2>p48Op(q2Lme zXzJN|;kbXaJTsz%RB4$|THX;V*!GZOPRwFNn~~xITQe)m2YNcpDt;LlDWPR`Mkkgw zgqc#_>_xeuzeiVLV&Y|&pw^);m+wV+qn}}J#P3Ylx#Yq+^d8Jr*)r#K*}E}66ZBE{ zeQtuIC%O$|XnQaI_>$&z*?TZL5o%~-(m_%zp&`E|U&o8k%Jb)|ppC7a*&Tte>v|}P zg=1smMi`&ShtUgAX;}rXHsrTEdMR-R7@z36=tZbB*E_D%9#Bh<3u;9-Mn{=}8p?f8 z!#$-Y0xIu6{P9+KRGNB`D^(7aMlXVTp!6X+9wG60HEM#LoQLeW|a>00Nus3xx^8M z_Q$B8UnpLy0L5xWHZfPxy0HlLcVjjKC?OOKQD2G2VaWvuN{H%DFiN&C*wAn^74E^L z!N7;V+6_>+iq2HGy`|sN!&7b zA>fXmij@rpls`cT1*{`Mls*3)*6B}yh!HD0@OrxaIbbG6 z)LV`S@>tpX4G`)^n6gy#3osuhn5Rc^P)u&|*xi&(LYNxBUw;h2Vh?6NU}-~`RbJnr zY!pq?Ne*ug^g$+R8o|XF!r~@@V=o@lBfBt&&jbb?rrtjmTZCnQJ!dnAYiqXULt>u5bW-4Mngv`KOD z7RhN!2%mvRUi>OM(uGJB2=vh{m=}`MG~wZLL9LJpc zXy?PFe-pgf5K~`3w?VzHS%H40cp;Wxh`AA*;Tr9LQGxC|(lyb}ZJOvsC?@~Bj_nQT z%A2tBBwTM}_L}Ss;1Bs|JLeEC!=Ia?^JQ7us`%yb=gKYv+ayd9W@WsoQotIUWLKTWCPtYFyO>DvrvxW#h=)JobNoA2>*8kQlX@)Sc>Hk)@&p9_bVJxye7Kb%m(w|9)!)ZRW3>hKL8X;f>!}{ zC|o6pSfMe(6Ym=U`~0c~)#+ey_9M&_OSpFoLgp&^YcL_d7JWWE3xY7y#eobsfm@XLVa>Qe~~qlP{vrD2AqvWE2#NjO{XvjYWVW;6K#Cf@`W z=WytQeK0=Z2Y9|!zUL8YZgaVv-g=E2$L>D(u(v|k_S;}&8mj)wZELr^aN-~K;@^Le z*H04g^Dp)DaarRzIUNzsS<$RutwuJaJ93EM1yV*T#{#1Uf|%pW*e`+F@d9cmhiH;1 zU(6k6yc$20#&xC@Tjh^!ZY(cR$n+JI5%8lW%a{=X9ce%%{a(^DUe?saY)a&?G6hq6 z=q}D;Meqb+D15E84g(K*!39zfDNWui!GelL^ewE(dpkMEN-$$Ge}ND@zqCES<7?SV*1Vu4Ab-3R1_ zEU%k#lW-3Q>1MIs?722wfb4~p$6Bx^hm;8PVOp+&Y#vBiKuQ_{`>%D29AE}YC|*j& zv4H}ZE<fle8a5wG;sjA;z_U41Ssj%N z^2uhxJU&C6uVdF8*gp9fOga zE&l}_bB!=oRtpFXuR+E0LoU`E+zNf7#$kXZ3X9HgZ0xCd!E2Fm^C~7k6WSa!z%eGN|g?4;;}A z&O^;(LVstSO(D+TDaCR}lwR)E=jrJ9d#pvry)^mg{#jFY@(Am-W60XYgVO8EJ*A%IG^T8TY?p)mja_ zZ#k$e}G&|ipdFTL4fD{>NUm~fHvHam;JuG0B!W0h@8B0&-Oi8RsM z5FAnu=K$y-*n#5(f*y_Dm`&gD3Y#zqlIRidlF?t_T43nmCvK)_X5&QFJ{|@5>!Sc28Y>{DJMoFO8d0uwM>RLu@_`szj;;fYefPk8)zcNVF2h^y0N z^wQI9gUeuquD7ZDvB?7p06$p;|(g{`OBh({d7Bec?5rXN>-)y3zqt(p}Le#QZI4G zXqy$IqqVs|UQMeW8>gBVgIeF$XZpeZ+zF|B!Dr$+E zufn}0Z$4~D&Q)zQwSK`2LQ*)lg5KtK-0K(5_iCQI?}bI9Be)f=PNiF(G}|}E zhpafX@LpLO(+v+5f&;y6)$#RDUfQcTncNGAzBzQlpI#Xy!&al=4sR}GfshqvhFN=%R#G7RsjKXszNev!c6p@_SwF+vg+XQG%7D*}(u&9pBw;d22iy%pCONH;5lF821CgJ%yx z-INrt4!7d8d(9~&q6_8Gj6|;0CJ|~xY$-saHcFMN{n%j!X9Ht`B53h6l9--f^w%_`dwGT{?4N5c61XL_yZ= z@4S4Ul@=;QJ_x=Xnb1#L&vondDoAZJ@43>u5r_?YQEY8Drgbd^78pSM?F9l55r1c> zlcM8=5)gqHOakGCNQB%VJld6KgXvBS_97gQyx(te5ZqM5HxG(h8h=coWN2m&jy*8I z7+M^`#Sm)O_ckgva|rDvcVh{)IQZtr_JdFt9wAT{jYt=X@Xhn0SW;SkTSnb;E5#}4?_mE^y3cj3(uFWPCZh(~+qA3!9CtqnI z`V#_xh14d1U93wFV>&~`V3XGx*+SYBQaor|05+tJKK|IFs3%rI9|w!Ah1k#3&W{Ra z@_I~e2PX1*7?|n*4X?-f?njH~HuJ4((og^J<72`j^9DYJe)5l(zr5NzKW^LRf({%$ z&x?O|yrh4eNf$;vzc1{$FAP#<|I8LdrOFD%)WG!hpO7#o{r@XBZgnB4?oZyf~nv8(I6G$D{*i z1{4~xSD#q?2y#LA1w;UDiJ~r(ejaE`WANF=kdMNSqZb>JvVl!9}O}D{^ zr+E$`pNnC%lwbaWg5scoe=H&LwD|kS43Qi5KaSkETjd8xGsxI}$+g` zGU*i8=*nMwwTG-nHyyhN)auyT6a5(eBnNQ551^ z1R87gpCn>I0Pk>HDN!L)o>Z>M$VnY7C9=BmN|c$eXbPEqX9!s?>8zSCY`XCA}w}>X?WSGfu22m0$6@s`g<@_2c z18E2?;2E&j>Ax4op@|7S5sqO9D(WQT&YBDtDPKwj3?q+nQ%pn~ax%RGRD*-p;xGwK za{h>UTYQdx_b)^V-lbb0<*OK#@^bb{>6+e|{8-XHX5g*{qK2?j?7#&HCt{~;F!1<5 zymA@jk036>%Y+KxUxtEY+tIP2^LBJ&gazWd1>rK#WHkz?NJ&}{LMtR?!dz0>r296o z2liu0iV_?0T`B%xhNURjTEO4Gt!o5LMrtcd&Xd1X4EEGILTFfbdX!$6YZi5^tJBuahNmfCJ zOHE#jFEOh$7}(|gpyBIl_iQk$HvCso2*&IsRV84IDQwDV&e3!qkhWC9B%O?8DL1G) zltMr*Qvw^@|84I1JC+KACoz#~ad?nqA{A$7l*%ChT2X?nCg~Jl|eFQhDtRV`N|*w2_lP5w3Ec1@yfAzlIbv6{bT2WUvi|4mc^)u zD}C#d?iFaw@liz!fU9yDh|`g35bGNcI%6>^V!3a5+Ks=KC(aOU`=m`K>##Oe7LaWENPE znmA$(pA76ZNd?VjSo6%3ZPFxV(>6&4Nu{0U|AIdt={GI&M$=u|Hm$9n5>F{^gp9FK zDfR#}Qeu{la@AZDT6JuDVao@x-5`U?UX()h6~-ADQ^@LakLaw0B3g>lHs}<@q?JJn zxUS$o0=S-1UOm&gT(lcC*pqlN8^Pey*$95U+ZCZ~gsvru1`Wr)9m$9k-gg*Ctt6<; zS#W7XLs>-DNq+fwNsEA+Me2XeccqWyu-^)l*edtU=MdhD0xt0e3|zO#D^~Mo!i%N%LAV%O^vW zi#D13H*Q%p;Su>67I0Io)VCltP%`$NU<#55#4Dsp0|~@jB@&**i(YXq97tJ>PLVSG zprGsY@N$4;3Yc`5_@8sf83KRoOR}9#qiESHIz5Q?7c7)q%XY|HmuWC^C~pxTTX7>i z*Gw?H;prYW5?JtpDB>a{iWs5HuB2MB2B9@ClyD?=u0dmhJi(|gw-Oc+5bDsuzpEe5Qrp6>dzJ4leUhe^!g0eQBy?Z21YdW{qI^w zT*>e`rgx@n6CnE}CMj1+j0|M70iKzjZNe8xR=NPTyMzBLawOC$e^5H5AX9QpM+gOr z!|922gEP7OETqIZSnp16sC1@qB00VRo|9Aaj+&vYP$<=TCwZUfyptT3GMV(;0Hu2D z!$eJ(&zwWQ0s+_qr^rlCTFoA)ma>mNNZD`Few=W~Or46*DE%FSK%I(PFJXQbZc4$F;l zkbDn)bE#e~;W2XZw%xsHcJcFsotx0PgnQ_Zx((=O;3oSv!5!sk`_oeU1DJ!T;MQOz zJ-cO^+fnXHnyX%H*tYVmeav#(r$zO(X!3?_NzlPZ#g+gUHloQHqH9plns=QLRw%2N zpm<$&@R#im^i@Rts+e!r(_Z^qe*fsQSpD`|uy3fpz~#sf8N6G<^5b^kBgXkz6}3Zk`Ay?yA#u^yo{`+o|Ng$o*yAZP zU)>td{qgd6&rsff`f5^BbMRL8nRv@w{FzXmaU{DgC3ckKHadXk4ZIj$${%}y$L6<< z@ATk5yV;{29l0f#VSKv9(@cvDyFgkK=a;fxa4*NMyy@OON;MnJ@Qxod2jakd`yvtw7evlO9PYA^wkUd4 z6n)zh_yn%PJm^*OB`hbR`1`1|70FOwt4&H|f z2sed}8ZkOmlNUX_Z(qhoEo6(o8^u@ORacx-J4G+{7k_`iv7^4Lt2oDnzjMG(y2s(l zl>5Ieq0dGWu*QlInIJKWzK~~zisNx~=LuK5DC`KYXS*K%1 zMX2kTd#Q^lU3a)f>s`b%g%70;abqin<8g61ZjuP zim1IEm7J27d*AtESFm2f@yJNGbA7f)M+YAw8wN`?1iMP ziuy6AkGfY#AI(r7P4{xUB8Gko2{1_kzxybsL1jfyo9BIy)KpRThuZ9*)r4e-1zM$8 zp%kFsYUe;I5thmTco??}(*&{wKpIvkchCu9tyqH|FL@k&2hkireSn9;;=jC576KZ+ z28W`a4cRy;Nj-crRe7p5YKApTRDo1e`esCOTimjbF?|a3RATGvA>sVb+Sj)%naS-j z`Cn}Pvvh>&uYUyT2g@SYB*BV;@N(oz250fltHlG2OkvxKzw z_l51{g6DPt^lIlooyNN*S>ydt{I{j-`=-{3Lmf0a!=>7pqR`khQvJLkc-o7AcDRb} zF{UlgKrn!<;*ddv_flT3-0 zM*)wS#5z8cZ7zvRF;TW5LzWoRK+v&7gA9& z$Xf=jnZ|~JaSU0U;`OBX{BPcOB6GP(EYVw9fJ)-m?x2THeeF(@;VilOA#)=^v{C$W zs*w$u3kBQ28{HBC*bdmq7fYB}drH3yF!i0ocOaTAdUtQ)Ej~u1hTJh$Ut+8_gI6vTMBhOZkj4O#)MFtgnTS$i%ISlm^zr|y|C%oq2pgX% z5GKVT@1z1@$9a8#)YD!o!hjX(v{92v`Of|qFH4R^)qAca?7Zaij4T}o3zUv-*r!Xa-zCLIBmV#DJJ(P` z#wXvowu^%jGV)VLbEYO_oFkB2fNvTkWMKa!A>*IFI7tRC)v~1oNdR4fCE+B2>2rgb);EMXNrOW*QKtKp^OFAKJ>{_!H-oyzX{?StL9SntY# zGmtM6)~4>#FMUa-Wc?e5vh+Lq>>W}HPl^vZrQf_QlVYDxkyCs!qj0d|f1`x{Z8pZE zIhfb8;Lt}auniP|?h(u{Q>&2Tpa0tl8L%pCmU0sg|4*W*de&08q}&+1OFogi*x?JdI+?mX$;jCu@FMkyGaTKe!_nQG zf06culS=#QSC>>L&~_!$-O019dEi|@IGG2i6H(rm^h?tqQw^>&DdV~Si%nvJ31F`t z2?*WW>C#!aAhIK|BmgOj5(y)n>LjpbNjZ$KDA?%;RyorYtT+lKKL4AvE(Wk>#aot4 z##KZ8Bxl>;W=Yf-66P!eWK4m5O{UnvHA@~n2Pzh!AGp)-f|3_%iy4*c8%AHb6w?l+fBcp#_W0Ngtb)HFjfpXGtYo<-yops%eQBrezs6xk>g|W8+Yf< z4feF+MovJn`FHLt?%@x{?yje3(M0Mc%T=XsJ=E*BKIu;S%;KG$Px5K^x0aG~M@#_J+C$cK)gk zfwp3^$m`xJv8ffbtKA0pjTLA+C-=f0WQVe=;2j}k}=P( z4(!%5u|ZrR*c#}zXpgD&;;rBa9;N3+fJ57WiMFfL+px_NY?lV_AP2T51Dn5itc6)`cbs6a4&&1z{#|WX}Ako2n zzhu(@(PnI!Gi}EQcKU)|0QE-yh-``oZ2_iSx>vk|U;@}f5ZOkn;=E|{uO-ci;N5vZ ze)M;ef#c*Bah)O1CXUcXf-l_vgiq`@N%C@bQ4i66f+0lv)xG#dcBFH1FR~Cd z^a&|888A24xXlvY8S$1cvUOs%yaY{V*k_HR2W`^`amT5`pJA#4B2VsCb{`;i9NE)u za#z0a@}zRnu8Na;>J4v4eW*nCT!VN1+kzPu(QJ~HhojZNv=r}{xB?vxVKIC|61j27 zhPFrKpzSiD_sAS)+-ME(vS^RVNzkLzsL1Yt>#~*8py_EtKKvcQG{V0k!Ib+2qxW~h z-F$RoQBU%aDki;r9^0O_p6P*X`kAR_74{|hl~}0dWaK|CAEbpqjXPwRW+m#-o}bRx z^en}I(Pgw90a@uOm1aIooi3pvb-@-Ij9$GGR%O&OTw0)i-s23gH|AX1iMJ9r16bi5 zKbKq(ixxu^adOYk*4;46Oxf5DY$n*d1>+;dD(=+0?(GudOR;c~#F%TkQ#VS^R@I78 zKy-Nb$7@BRee(Jwcnks?26~dq!_=OOcWwj}mEPYo5$u*Fxxc6T?bHcjI4M#*u1k)2 zt>l+5W9$xPXG6TD^zm>lLPu~-K$S|A%u#>5k9X4<*YeWslo zDU%y~f_VV#xY`Q{KK)UJSV^faTXAoSK*`B~_9g8#muhDx0iq2#`fwc(;Ue{fOjl@f zPVSOP22jEjp1L<_Knee2e+|~Uwr`{^?ZqnlYbgh}-AHk&eM+sPu&nT3rw@e(;rPRy zb#bMv{^+3({XC;!+5!H^@VoaH8-?@U*HnZ@6n9jRxF1JZS>@wB?X2OPZ<$WU>OyKz z(t5KL(h+|CS?XAKhsAp1b@J&X{y;+-Tc@Ru z7jc_9&PW`hjeXmcm3Mx1mesey&?xqs{N7;S6xN_n_+YsE^_DCbik)5P)5A^JF(1D6 ze^MgOcZWuPB>kc8TFf8ZMdFP0vDx?tVmtW%UF-6(AZ!}Oe$Trc8II>ts!fVh?C3vG zvs|M`M(`VS(mG7fua={aY?{C2@f|(d`~KhZ_8xiNdH59J%$IW`n>}r`JZjf09h|dG z5cMCgW4NA;b+g}}eVVFJoKwsW^U8^3E4!tYz6tZ7zP(2~K`Lo*79I+!qvvyY{t*@* z>UTML63aqZZqx{Rlo0!>{C;!NVFiI;AUMMNkZT*|e#C<)W2)iPim&RnAU& zImgs%wO48Tnl2a^>7jIcSx1Lg2!l+MxW5mM6({0Z!V=+l=-~6dq3-8`(NqQe*f{6? z=nV|%CG+AQb<#qs-N7rAU3#m(;X3ryN9iu8n#XKm9n=vVU0<00;5%84U#K;&FPy_- zGTns!%lk)3!OYR>mwgRg0`JiAV4>mRs0xzxVN1)9rPl3-UDa1@Ikn#^)-v_YivBkd zncVBOJ)<;}$onMqOm&6oZf0rq^ZY1!u}OuAD6T75SpkkH1DxY=lMq2Yb!0@8I6) z7`WP3-{!%!)b-wT-L<~c-K8F|jFJ8DOv~K=oFk6;J|65f+3Yd9A^x6H=Rtz)nd)Z^ z`OYa`q^@ua-s-(yAO4bw`GWi{;U!jX;iejjM#cWfMU0-EUk_eloKz&)^R^GF)?l}S zlanGT`LGIuqDIa)Pr$xP#1{S#KB)EeLzl=zMS8^#O+MM2%jKM9niZZp6*XUquA=uS z(NE1j$1&Op)w-ihcXw<{bTz0c?yV`79n@0ZN5CE=Kuw}+f)|pDugo50IK^--e+Bnq zOK|lfVD&D5$83wNho7ULdXuwla4kVc$#p};zQ_fPg*B-f(ZRRp4{oZ--^%-XuxI%O zGJIh~$X9ed%lUc`TqwEL6&RAmSZw7jBV(0F^9EJPl=h#aIMz)z^#!54>jKmJ7d=Ps zsK0ILRS*o!+B0@~v~NeHx{T_%mV-=6Q;Jy6e3OON;)u+j$`qU89cSln z%WHKW)y-EYugFu6=|1=<@kg1%OA42Lj4i)3a@KTEe;p&8uuC)R+~J=rZg&*$%Ayt5 zTjhhAUp-zpm`+$b@Wtzd_E}#akBQm76FNLvuB)nf4YgRs-e&a|s^D=iR8+2AgAP71vD=RyhYy&cf^*yN{Xtl!(!6bT8)ywqDyo|1##N`#+gESCj=Fs9 zlBZ$SDMz*BAL5e>lD0d7Qe}6;sylPfL)UY4_WHzt3i>K;E0POV`Y);nO`2sN`^3Bf zudYLt;rn{GV8d;nt3q`^sW$m|jOT)t(DkF14r0`53%01(JA4 z))6YCXjd^vMVqC<3=?CGlBJYwhOv~L8T&T)-I+mp*Zb4=`}@BC{CMeh&vTyjJkL4j zxz4%w09G>0qSd^3#HaFxW?Hq|#qS3I$lYSvy@7AjVwuL!j8WFMvb#-*>4`9NH5eE* z?aE^XnRRUMd6u*N6Q<``BVIQzpia<#Ixcw{8QEDKvNT=!5ESAa;4UmAm(}(*cla^+ z$r8|gG_&%T#>TQ>?Jb_zLe-3{;g|&5npppZ7>E4Nl}P)fX^dKvTBHS`qd9cGEU>fT z`;bRT4h8~?Jn!mMR#s3;Xh@vR!#}mJgyx)=$e<$GtcFL%#sVxen6!|<-l0gNdAvxy zVC8Vlhq-gZ0$EerAX?Z!^`T@QZ60{mlLkSO4w$%@EjmZe!?icrza@Pic{4H{j3RC7 z>(T*XYB@ng#4&^UE7jcONIaON+eYop6YGrcEh|Jn;h<#Aa+e{4H}oCyYV z5u|Ytc{LnSF_<`+Jbw*_)`7;mO&8wD{Dh)>K~ZjJOYN6UG24y~oUQu;#az%>f0s#f z!e{{b)8iBtFY^lrPP14oBx&={$xhhxVd`Pq zI68srL((0T^^9#l@(Jx`&ekY%BmNF*@4|_>42n%Z<}>UG$rzuYe+{KJ*Vc!8M1t(P zNCFCEWXtedl8)5=USwP?Srkpu(ZmORE2sf!2jGJenU!VS)+Y+2TtBh?I9__G^xMLS z!shyYDTaC+d$%+)wNhhWPva_??+KihNqKYOO1Mv3&lb6MvZ(a>wWhlJxlN&_?{T^b z)~BXiR9Sz1{Uy=?JPT^$f*`|&t7o>*RHo^^dFAE~YX11L{u4Gv2WB!RZ2AGUxmWbR zhQiz!48+fOrw|%)B1jE9D4Ts3+F>yV1{U)A7LueQrDh?BMAyTnCr`V7nDbZ5nnX_YyzBBGph(M`gjkd)LZ?LewzqV>iKcoTYYr}N<;Wu zc%K)RRx*W87?K~-sl%m}b$?yxhYiK!@>S+D7Q}IANM9!f?ES=BE7S-Mra8&X_SRBt`JeZHa@Q`DPgt?&KaKfo9q_T# zQI#E@zx#Wj#@`Q3QB+Y=`OWJ|Aaijgke(;P#RuwuZ~+;(__;f|95Xtw_8{EEy8%{~ zNWscb*!!gGce2ZzxNRZYm?S&4>+XdTrXPys zDNE6^P5s>K_HR>X+kHFNCsE5g^SN4|>D0EwfG2mPE*}*b9A);-Q+{lkjn-bybM3T4&~Xgl}`RHayw&wcudk>EqC1;&;(|yOpi3O3DnrxXl_N zuP>E#yMOb&$EP3Nau;5I4?mu$p4RHP_a*1m*%n(@JG_xYa4ET%umvz zZiGR=z1BLM7yJdYYUVI`pJmrw&0;Pd>#<3wo?j%M#bB1MJN*-jZ@uJ8TEGOO>noBvAW zv4{JfuGMsrsY_m#~8&C_m(R4smE z_StdDWJH|z=Ja*2q`eerCq6ZMcjj$*V@*Rn_s0`Q-|ep4y+x+swzZY&@%`6QdXDUU zI{anF0BT^{0AxTw=vt4##wRYHzvO(++0jaNOKwPW1NCh$khVPlN)_%O>=XMO*MLt2 zJIHT^UUfUTqpbL3Wpj;s#ms|I;#H3xCn*)nd%5?o-4jv8c~0Fs>`|-6htE8+}6E zgA!X3U(#H9atUpC_0ng@YZa)NYQegFkbRG2@7!&>%eF7;R8dap%dU()8LB6**|fbn zn4y!QlrflrIhFhh`Ls;XJy#MzvXCu z*nXOPlq`IpK>pxKY2x0*vCjF&bBLL%^V(Csqp}li9YKxLx%SuX?~v}1WciG4?;F@8 zA`sF`?gveajpBuh*$=V1ZB*x{KvJwz6uoRZk|VHs?s_l6%~=N*pd{M>vG?ZnwO>kb^2=_icf=?;&1J!dis7wUrIq~Cw$j9 z=v3;De)0UH0lfgL*|W1da}9J} zF6K!*a}26@^I_rx@7~atAF?!4c6b;o8|7|?Jefk|hWP4FN}}U4P1H^aoOtu>+`;5j z(y5JK<(}y{c65R*w_F{0cjw)+f~tZW1-+92laWHr+^v^4UQ4>>Aw*V@R9;Bi2Dz)2 z?CI_44!eI^@QtU@-Y=(H17FwVXS{&~26T_GRrl)H_|SEyv4)NBeHQ3o9WqR zVDClBn=GGfoorGwfHZ%t8-WeraSD*`&h?%tK^^mE6$!Q6tUOSXX`3feTjTbe#k$Aq zZ5Hog@9(;Q{XX@9+k>wO2NJRpwA;@Ce#$q_ zFD=k2$i>Ow(%iEBxBseLJ->}1)O@}uRo6($u` z?+(5ztJJH+SLsx}eXsdG|AYDmOtort-ba;>xiu;^xwWdbd39=a*m{lnf=}9?iavus zmoykOy!&$aOZ8Xtub&!^H#Rq&Y3gWpZtiRGY#D9!Yn>-tAhHmzv~6m;+rGU$l_W#T z>QL<{>@?{7*k##8=yvKJ{09F<{eH2ByXS7NSnsnw#lE-w2m9*>YzDp$dJWDGT^{Be zP8``il0)84{zy4V`9A71x-@omeA{^Xgz`k`BFE1pad7E9qe}ubPR?7GEZ@NkeQ3KyTk9OkGa5MzCKPaaB)RC zg;ju;3&7IVMOT;G1?mi(4aiNaV4M-C5A%fiSb8})xd5-`>%&#W73flRbwLLKxd6<{ zN>N;aA==7HSzLj3tiUk<3SiQ{wRa4_JmLd$vUEY%fQ}d(1X;QGBWyv2{s<#WnxX&) zBTEHwMVg5K?hh4yIi^rSUP0kcUj(?_qz4nO6uCUA1+I{g)-bciy?L{AU+viv!tdVv#H%AQn-?X*Q9Rs6(w5@48w>S0x1 zCrn|>RekVdXg$8cRpy;;Q>MW&Zc9udiK{KLMofk0(b(zyh1dE1r{77jo+g(HA!EW2lI(IjVHk0=eEyl`0~!z)cD|0Fejmjh2x|pAL}hJUL4Z8R|#Y< zmKqfDl{+Ni(PiDc57Li{Rr2Q}th4Y<*A|~|01tTRBkU1A(|PlwWc}$|nSFVL#F3qI zJCM^R6Hb~_Tie=RS)y7kbXcapSH5b8$VJ0zh&C^$Ux^I_ip`e?7$?GeblIk#5{D-) zcQ=f^KW|Yj-E8?iNuw?r-fR~hRPohp&^s_tBI#YabXP!fcu*#h!9zGx7OVq&7Hc|s z{I+`U#}J;8qxpn>?#em~i}HZv^^{Av%rt$;j>I*tR$mX7x+!b z0}~m{PNK%25`VWEWB^OI1Qe!gz8f&YQQ}JUZYd^LYk_68zW@e4l>&^RX-ij~W8)Bt?sXEm|(WE)Udp$ z*|PS?H-jV@nu)akfW`5sBZU5y1;ZZ)1MVJtwW4$C1hB|Yv&2f^=xXCjrB3;2uBd%Y z;z6{VROj zCqd0Hs45An_NeG)f!>mNG8&pg{dV~op&fR4q^u_u2OcWgUI0c$E|m2ymMxA(CX0!Z z?BBMch-aXfd|}*h&A?5c>h95xsMCvDwpZK1S4NP1d7&+5f?Gp1Na|?lTjI5Lu>{nv zbaLO~)WQgAX|c;5KQaP^L8rmC{h6?=>1u0yf2yTXN^b~f6|f^Z0`i>G-dX;Wo4IR`(hf67j}TFlaYQh&CLY;Oow)k*G+ zIf=5XoVSNQ!@Ntg{@@|Yd>@Yp@d?^(5Ah7zGEIJNbL=fRwTIl{F99Ug9JtiGA zQ8v01+-sB^3!B2v_T94MFB@YG37i1M-}Twn^__qI+2a6RyN-(QO>M~e%8}9J`H_(+ zO7lW+!>}$HO7>gA5|DW9A>R2){pm@`tUUvxb(u@U8lR3E+AM0G)R6{n=SAV>bLO){ z{WXJT-vv@P456aG%kFC(<;})94ayF^O+IaX!4~Gw4AHfp9)G#FGSeY9t~$GQQj4Wm z#=G|Z{C46aA54RAtVQ+s+t!A$p75VKY+H_KdbhwUp*V~3z@NLlSaMYSuid^`*tz~^uF-IQ;@nRcS$>LHy0X$&Ln7EJ&3j-M^m8}?%`Wo!a)6s3}vCo0j)(&`uuwadP7SC1gJAXN0UKeB~h0-M@<% z<6rc={kMquvgxQ735fXjv~6~)k@n&5Zus?Z(A$$IO$}yw`@c65ur~}kkqcK2CJpHw zxYcGGq9<2udh--ByWskl+WS(rw4_05PLI7jL@r*^O+Wm8z%quzb7;l^fp|P1F^N7G zZ){){9kqw=)lpSxiRT6eccLEi-%#f}EGhBKU>Ch0bQ~>kC zgU5M_metW0(hT-nN~Fl})qhyId)95R-zE=$+-7$(W>%JDI(y!S4wtxTY;Y|4&>p^Mfg4t$KMEh|kzYl`D&P&@oL462SLl&-OKxfwNR26;(@ud(jA<`0`R_>M|4 z{PmRo=+~k%XQPcVs!sZZ@9Yf|IjS#jsE?dYO#B%wYJt@ZZ0=hQ-%->5@= zA0<{rcCp900hy+qTe}Yv(@2!9{n#4Ns> zo4-=}$6_w`$8XYNsWu;Pvfh%T&doaX*w2oFaA>T|J9Dp2wB7*|bHceG`%Mh8M{L3E z-F*8;+k2HSEEXo+GLv`@6D2ix9=*pR`suXaZ|*jT~4DH|fh zgue67=!J=Gr9Lf=V@6qZ7_ox)PNo(Z~N zQpZXC*x|~8f;PKQlp>P11vl}}WJ*$OO*(LQOOUc*r?;+x5IqVzx57eU?^MrK?+9}%l^If7j|f_t|H_nxPqohay?D_0Mzexcyr zZNa@jEpYXqpj|0w>6Po3q)jvCTZ5&Uiv(Cnhs)%`$QO%|sl~ipsIxTd{+bCZ;pL>( zd%3fM6=#lyiEX1+t(v%b#<%lvu>}|EScfz#SmlEx!^~4*$sE*|#dTb$6CJLsV72E6 z?jqQ>;69&&{!IA&c0x9+YmvTPWydrL-1 z}FA@AvdP9EaPeC2{-KK|6$z#opc5H zVdsf2UVF8PSA?LKBA40z59$cd`>QJ|>h$HCBG%vLKUTb?5YW`QB*!{rQ8qd9UAVS; z_=Hbw|AZq61l=NbH-?9NvY`uxQVHdlHz#PmA;UI?KMMjp_W-;pF4Qy^ti1#;9JY3K32Qj+hkcrP`(D<|Gg47* zHDmD=Eoykr%adRAVIz&nHSs7o5)Ac2p7Zsa%_qZ(f{3uWwr0}HTD*)(wU3~7^e_*} z9vzyM`ObX4s`LEN#Py|tuP29$^0LA9HP2iIoorBBlXZN;Gj^Z8@oWJYK+c!=X+nxd zrtYxdd=3Pbh4-Lm7raB9E-!*D7DfuhKAv;cEyABE0=BTt4+kn^<|{L{k%Qp45;V1` z`&Pak`C~(ULZ>$&ZW{ZD_{LegzrEfkhLwQHrDo3}VSWo+#`$y>^5&_^cCquQLR<90 zkpg1at>hEE=Yo}aCo4vCpJp~7-ue3yZhnA|nnCQJZthmTQiQ5F`7V8r5FU1UG%{|` z;f%eg97P&#^KAo{!Pv}5a(9oOtVmkh!q;cFkN7=q_#9QKlByx;ozKNi8uJUgvBSy! zLF%|jQL7(xZY%0u!n5kK%3-RvCs+p9O9(I2&xtnyhjt-scrkB?^<%JthxRr+Cn*P> zI6Ri<4(~mgz+30Egu>f{1vGo}{KUL^IGn1j1cwx2&YCDRYp?5T zgT@qYAslMC&dYm4GJLjw)Hs)LY0L^0f)nAn(FqxbLhGx0{2ItL=k`yIy5sdp)^*K$ zDF<7=i^7Uj>LLqy#foor;}>#nrA($rdLJ>vG`M$6nmHxFNMnin8|+oP3rozB{5os$ z)OZJ9k<^G$bq)Jw2Mz|yjn^%`c`-Y2_j`7K-edsNseSt|gp;7z5s=8q_=opL{q0ju zp$k2|NTS)N&|*T_wlYzOdyoLz+7!cgJ_q**@s6}4N!F$~cW*jP_<+tDs$fhNLhJV6 zxYp$k?!&d;k_{WaUUlLL+%^b+0{_kvr1Es~9b33PD~tV}3&V4JW7U>AM92#4Oh2jB?PX3ogcVq551oEcq|mz{5#3piLLcqfh>nVnp)h8TxcV z%&w*lLrOFEOwUuQQ%a$wnWn?gGYY`> zG=)_rPK_^s&iQ=5Lex0w_IyW0DJ*nCo{B@xASGzmUh22g!NQ%S!m`jMkFuuMB8#@{ zOCutSXvTGHf@ev+3>-@#8_XcJG6CSXZ8T)?D_9sEMy6lKuTaSCouv1aTbtl<~^+Z72omO-fAXmNL*~dwzOhx=glHtqjJ2--cTHc7)CPL{Pac16RTieJ|m12s`vA zuuZVlZ=nBxycT@z8bN%8;|45u31kyy2SeVUz)s+OG(={M9!;@jjY=Tv81$=PPUtPH zSqX#*BZD>TQf0v$Cic98@UN6Oh-n?F(S*NigE8CUFjA8jRSQultisWSzPLP0_ zc+pw>3EU;ckYUJ>$pMYQ%9cRZuZaFfaO1n*=%?yUD2E7OWU-L0JQfT$F|Q*pnjlF0 z8C(e7!>Bi7RBVJMU?C-t4J%~-2%dWPN8bM+az>w>Aw&Q}=N?Xwg4%cyiXqFg8DOn& z!VajBmsasGJ2Vn2QZl>=^Tu1Ne5JGwvlA=Q<;RTCC-VFmJe0ime}TP*ckMes?y{r} z#8}`MB?2Eq;C}{3+04(!5$0hRm!>$EYD5+Zd#P&Q3ra)bkpO_S7zGTdnSTDhl^QpD zJrlq8x4;B2u+Zpn_au=f^|w-WceJM$9rIwt!wHoEdF3q$u6Bcz*4Xh5kM$UssNHbK zKrMV%ZHxAJe+dD=u^$T-a_v>&$&~3ePTaOw^aL0(!ID(xnb})=OD#CS+koNn5-@fy zPX%-D8`$xZ)N?byd{9cC4@`j3)RlCZF%9gZ&W?TnhEV~`6kQr}M$CJDif3sjl+@F} zzO(^KGMEwbnok=qC|d&TpjCU!$1m_#Gnh-FfHXD9&EqQ+rE2;PP?MpC6q7i{JoNf!ued^FN%3jP`avx#>5@6BsVn`r9s zde7%|U!m~Qgo2AR&@hJ3^)!=QyQgF?hSHS)%Gz&7XxM<+0O7d%j|v1Z-9=(UfcYxQ zhTtOBH3iYwN!>s!l4%lI+yN!EcLJbcU`7K2eqmo)hk<=)V5j>+rc;{X3*(vh6c5ss z&iIS=T=-qoIiRs)fC7mNn3$EQcY$dQbCCqrty!6tftidxM{k5eIvbfW2Z;|l8l!A> zLa$*}N;3E`QdpIaKY|HZm97<}3pN5oA#aax28%y{1@UIfLb~We&AdFyGdQ5!tFr$Q ztol0zX_N3DXV8VCf0~_toy!;F#tQl&J2gtxQBCRhh&daLdX#Z5p7RYkkitEAI5zFA zs@QT`$cA|2vEDJ&t7q{+1u|txOK%SCKcM>5FdN=66~N=GGi`bWy1-I zz#9AtIe@)P2~1VA%4KpoE4nCvcL#$vogDtZB`9ZTPgB=Ji4l$Th$?49BQ2s>{|tt& z1R)So#Xv|chx5TdgU6F-9pK**DFEbl%LyBh9u@=X;c|ek0c-K5{|@{Q*lWSMl`Hut z3xJ!>fEOKk{4_v0WHa$ZR~{#Huh$BOF|kqOe@Osv;9rqvILFM8WK3hc3eG5AmE;ZR z1ynAp!L&jM=z{M4m4F`;u%0-j_)2Rd3e;Odp4>N6n8=22A|fjC!U%S;@BBD(lyH&{ zJwE&CYsoiLAC*J0EDr{`d-m?PDX4`Qox{~uN_jmOhp7>j zBgkAuCKPlDl9jYAIKD$Gg3M2yy{sQD#)UdWi71H^?w6R^QNqiLH>T_jx0jr`Q&z-a?lm6NWFi=cl z3*AMt-jHI{kr&Ut$WEL(rh2U-ftj>5_*RE-_=;g%MRh^79XMvXP4nD1t|FxwIlv0= zR_a;GvT@y)6V6fgMlfvRLb*_0Fyj?x$|2_V-UO5@MF5b>3|@~ZybWj-O;;GW`X1O) zVnMfsnI>9?7X^5OaYcVJTqV+w?bV?vh+?9(Njkj=q*nmn%i5-@rH!F5ka32} z94PN(&bH}>uY?z3(5$&}eIdc&-dRj9Z!RqV3a+=&Z3aaUo_rpv#lqSdv+!15S%)a5%E9r)<}_oO#@p-a1@goLYR%d^UkN{mlGu z3k1{92KQ?R{(#Cq87=^NG6n4Rhi~Tj{Le#dWEkvTY=1zTX4AGpjsH#E*s;h^7>r>0AKA0psGyvhPz-|?7BBVQM z%|Uu57t%z+w?OiGhbCaT1gI|hHJlhy8+#Sf_ORCiGF*JdXC&v@{MO{M)^y@fpnq~+ z`X({!NWY2}vS?&mL(+?ooe_5%u60lk6DpK#{XV}pgxt5VQxA>H2Y1`~*am0>2cLwc zbxuyk?`^Y3!t6w>E7Qy3W7;T@cXg$92x$UJB!&SLa?bFP84JdG%j_L5_&v8qg%7t81 zs=xnYak|li>c(lc5yj)=I4M`sp1Uzq`-S6Qe!`TIl4Hrq=3Am#3SXi_ARKwqFBU>f z=0=gHOuSz=ws_n~oj>chA!M@OD^b*<_hU7|M)+Ol)Ns>{`MPWIR^#JNA8Sq$+FSLj zEUcR#iFL`wb;$z+Vc6R|>1VxoYyjRK7MCzQI0&-uLr!-%r@J=2u~y9;G!H7=9YTV& zs=x>%Tg1|8(zleQw^`yYCHmxfR2L-2&QDG_6ePt`}}?!$ZH8Q z_yPWL9*{oF7uf5l2wL5y2nU(CJHu@hX!|6OiPNuZ`2F~zuBERdg0{8sq?zf;p+ZV3 z3Tg~SW-bT^X9tACj~8>a!T!KDM-LZ-xTA}!J5)!4jKfQayF2ShSgV-Hn|bNGxVaw+ z^l`BaG`DgJ^l;K}mH_K=YWr*YL%bjWH*tT6Cls#fuOs0A?4fkg1ny~Ikc2oL1>vD1 zp(Ljut0u1?q01>QF0Sq4d`|P2!NFxZprj+=hCp~}fyCCl~|-RDcxZlt8PT0YYs6s0r-fboO;}@zK?D@_{)zAjA#a;Rtt6PZu9?H92`X z74hBH?!dlLBwR+D#^eY7vUF__O{Fy|((R{l{~P>Is{1>5t+vrmssj~(>heFU4gfXv zeOw$6Fdr)z%v1M>CB2DM_eZ;F)2hs1&hF;|41oQr zx{C4&^0EpFvI=Te3M!h)>Y55lry2BXkp4za*TUrwh=9Lwpaq_#i}%maADZcU`5}B@a5s18f70M*26PSnChgyhd^59E zC;m3}A&{Sa2*js&8Tvqt1JE*%TJE|$kDmrTbd=(wkWi`}Y zRAtX8t2wHiQ*?5aSJznKyN32ZMmnSQfFTkXW@PlJ1lzxS{bBIG%y=!k{|Z^# z8h^b1Z*%>ziPj?gx4G7~#vkwh+gyKaqO}PBZLYPg@yGlBHrF4UXf48jYA((nPinyH zYB~}~;5qC!uhISZgeyI>1`=3W0>0Zola|3NC@82Ys3@xg$-4|l&llka^Vz+c^T~kd z6aeU-9~oq5Z?(~%igy3gQ_-1~$D%VbG9cjL;Ge`>(K6@VYtvqtAJ4)5J}&3DIpxJQ zfXnKSxT=bZl8QL3g7%}VpsEJEu}Aw6hpxiZ<$+h|{sz-f0-nczf~hD1E%7T%1$ZCt z?|5o|=cl5msPqe-in`(&JcN&fJMf&y%?Z5cXXzg3BCY|L#tEd3J_v?o3JR*+oRX4; J76-XG{~zyT3()`o literal 0 HcmV?d00001 diff --git a/website/contacts.html b/website/contacts.html new file mode 100644 index 0000000..21a4fc4 --- /dev/null +++ b/website/contacts.html @@ -0,0 +1,74 @@ + + + + + + +Java Bioinformatics Analysis Web Services (JABAWS) download +page + + + + +
+ + + +
+ + + +
+ +

Contact Us

+

Mailing List

+

Please feel free to post your questions/issues to the jabaws-discuss mailing list.

+

Contact Details

+

The Barton Group
+ College of Life Sciences
+ University of Dundee
+ Dow Street
+ Dundee,
+ DD1 5EH,
+ Scotland, UK

+ +
+ + + + +
+ + + + + +
+ + + diff --git a/website/develhome.html b/website/develhome.html new file mode 100644 index 0000000..eeca0f2 --- /dev/null +++ b/website/develhome.html @@ -0,0 +1,128 @@ + + + + +Java Bioinformatics Analyses Web Services (JABAWS) developers documentation + + + + + + + +
+ + +
+ + +
+ +

JABAWS Javadoc

+

Data model javadoc- read this if your are coding against JABA Web Services

+

Complete javadoc - for developers who want to use JABAWS framework and use Engines and Executables directly

+

Starting up from the source code

+

SVN source repository:https://svn.lifesci.dundee.ac.uk/svn/barton/ptroshin/JABA_r1
+The repository contains a complete JABAWS Eclipse project. To use Eclipse with this repository you need to install Eclipse SVN plugin which could be found here: http://subclipse.tigris.org/servlets/ProjectProcess?pageID=p4wYuA. Eclipse update web site address is http://subclipse.tigris.org/update_1.4.x Take care to install 1.4.x version of the plugin, as SVN repository will not work with more recent clients. it would help to install TestNG plugin as well which could be downloaded from http://testng.org/doc/download.html. Please note however that no generated code is stored in the repository. That is to say that if you like to obtain client or server packages it is better to download them from the download section of this web site. Of cause If you want to make a modification to the source code you would need to generate distributives yourself. To do that first generate JAX-WS artifacts using build-server task from wsbuild.xml ant script, than you could use build.xml tasks to generate any of the distributives you need.

+

Structure of the project

+JABAWS layers +

Layers in the source code are defined in a different source folders which are: +
/webservices
+ /runner
+ /engine
+ /datamodel

+

JABAWS project is split into 4 layers. From bottom-up the first layer consists from the value classes used by all other layers of the hierarchy, in particular web services. So, to be able to use JABAWS one needs to have these classes. At the same time classes on this layer does not have any dependencies on the layers above.

+

The second layer contains code for execution of the wrappers, which are the abstraction describing native executables. The code on this level code engine. JABAWS can execute tasks locally that is on the same machine as JVM and on the cluster. Thus currently code on this layer contain two engines. This layer depends on the layer underneath, the data model layer, but is completely independent from the code above.

+

The third layer consists of the wrappers for the native executables and classes to handle their configuration. It depends on the engines and the data model, but know nothing about the web services.

+

Finally, the upper layer contains the web services, that depend on all the layers below.

+

The layer isolation is archived though specially designed compilation task which is executed sequentially in several stages so that the first layer compiles before any other layers, second layer compiles after that and process continies before all the code is compiled. Any violation of the layer boundaries results in the compilation failure. Use Ant "Compile" or "Complile_with_debug" tasks to perform the staged compilation.

+

A client package contains only classes from data model layer and a simple web services client. Framework package is for anyone who want to use JABAWS framework for controlling native executables in local or cluster environments. Framework exclude the web services layer. Server package contains all the code.

+ +

Running tests

+

The test results for the JABAWS package offered for download can be found here: Test Results
+JABAWS uses TestNG for testing. There is a TestNG plugin available for Eclipse which has functionality similar to JUnit. However, no plugins are necessary to run the test cases, as testng jar is supplied with JABAWS together with an ant tasks to run the test cases.

+

The best way to ensure that JABAWS framework is completely functional on your system is to run all test cases. +Test cases tests all aspects of JABAWS functionality. Consequently, one need to have non windows operation system and support of the cluster to be able to run all tests. If your system does not support cluster, then you could run all test excluding those that depends on the cluster. +Several testing groups are supported: +

    +
  • All tests (Test)
  • +
  • Cluster tests (Run_cluster_dependent_test)
  • +
  • Cluster independent tests ()
  • +
  • Windows only tests (All_cluster_independent_windows_only_tests)
  • +
  • Performance and stability tests (Long_tests)
  • +
  • Re-run failed tests (Rerun_failed_tests)
  • +
  • Run custom test (CustomTest)
  • +
+

To run the tests you need to download all sources from repository. Once you have done that, enter into the command line mode, change directory to the project directory and type: + ant -f build.xml <test group name>

+

. Make sure you have Apache Ant + installed and path to ant executable is defined in your path environmental variable. + Replace test group name with the one of the names given in the list above to run required group of tests e.g for running cluster only tests + use the following + command: ant -f build.xml Run_cluster_dependent_test + If you work under Linux you could use a simple script from the root folder of repository called runtests.sh This script simply contains a collection of the test commands described above and paths to java home directory and an ant executable, which you can define once for your system and then reuse. +

+

+

A handy feature of TestNG is its ability to re-run failed tests. Failed test ant file is stored in test-output/testng-failed.xml. and is used in the ant task called Rerun_failed_tests. So re-running failed tests requires no more work than running any other test group and could be accomplished with the command: ant -f build.xml Rerun_failed_tests CustomTest runs the test defined in the project root directory file called temp-testng-customsuite.xml. This file is generated by TestNG plugin every time you run the test from Eclipse. Thus an easy way to run a test in a different environment is to run it from Eclipse first and then from ant using a custom test procedure.

+

For cluster execution make sure that the property LD_LIBRARY_PATH defined in build.xml points to cluster engine LD libraries directory in your local system.

+ +

Preparing distributive's

+

There are a number of ant tasks aimed for preparing distributives for download. + Currently a few types of JABAWS packages are offered +

    +
  1. Client only (contains classes required to access JABA Web Services)
  2. +
  3. Platform specific JABAWS (windows and other)
  4. +
  5. JABA Web Services without JAXWS libraries ( a the runtime dependency)
  6. +
  7. JABAWS without binaries
  8. +
  9. JABAWS without binaries and jax-ws
  10. +
  11. JABAWS framework
  12. +
+

+ Corresponding build task names are: +
    +
  1. min-jaba-client
  2. +
  3. jaba-windows, jaba-complete
  4. +
  5. jaba-without-jaxws
  6. +
  7. jaba-no-binaries
  8. +
  9. jaba-no-jaxws-no-binaries
  10. +
  11. full-jaba-client
  12. +
+ +

The easiest way to build all distributives is to call build-all ant task. There are more tasks defined in build.xml than described here. They are mostly self explanatory.

+

If you made any changes to the data model and would like to generate a complete JABAWS distro make sure you have rebuilt jaxws artifact as described below.

+

Building web services artifacts

+

Server side artifacts should be rebuild whenever the data model, meta model or MSA interface were changed. To do that run build-server task from wsbuild.xml ant build file. WSDL files will be generated in webservices/compbio/ws/server/resource directory. It is not necessary to edit them if any of the JABAWS clients are used. However, if you would like to generate portable artifacts using wsimport based on the generated WSDL files then, <soap:address location="REPLACE_WITH_ACTUAL_URL"/>

+ +

must be replaced with an actual server URL including the web services context path. For example:

+

http://www.compbio.ac.uk:8080/ws

+

JABAWS are the standard JAX-WS web services, which are WS-I basic profile compatible.

+
+ + +
+
+ + + + + + diff --git a/website/download.html b/website/download.html new file mode 100644 index 0000000..c64991e --- /dev/null +++ b/website/download.html @@ -0,0 +1,124 @@ + + + + + + +Java Bioinformatics Analysis Web Services (JABAWS) download +page + + + + +
+ + + +
+ + + +
+

JABAWS Server Virtual Machine

+

JABAWS virtual machine is a way of running fully functional JABA Web Services on your own computer. To use virtual machine (VM) you have to install a software for running it. We would recommend VMWare Player for Windows and Linux users. There is also an Oracle VirtualBox (version 3.2.12) for Mac users. Both are free and installation is simple. Jalview can use your local JABAWS VM.

+
    +
  • JABAWS Virtual Appliance: download (520M)
  • +
+

Please check out our manual for the detailed instructions.

+ + +

JABAWS Server Web Application

+

The JABAWS Server Web Application aRchive (WAR) version is for you if you want to deploy JABAWS for many users e.g. your laboratory or if you are an expert user and want to have more control on JABAWS. Typically, you will have a cluster or at least a powerful server machine which all users are willing to use. If you only have a single server then, you may use JABAWS Server Virtual Appliance instead. The server is provided as a self-contained Web Application +aRchive (WAR) containing all necessary binaries. WAR file can be deployed on any + web application server +supporting at least version 2.4 of the Java servlet specification, i.e. Tomcat 6.0.

+ +
    +
  • A Complete Server for all platforms: download +(45M)
  • +
+ + +

Please bear in mind that if you deploy JABAWS WAR on Windows, only the Muscle and Clustal web services will work! If you want to run the other web services on Windows, then use the JABAWS Server VM package instead. + +

+ +

JABAWS Command Line Client

+

The command line client is an executable Java program for scripting against JABA web services. Its also useful as an example of how to access JABAWS services if you intend to use JABAWS in your own program, with functions demonstrating how to discover command line parameters and presets supported by a service, and how to run, monitor and retrieve the results of a job. Note: The client is used in the Jalview 2.6.1 source code to autogenerate a graphical user interface for JABA services.

+
    +
  • Command line client + +
  • +
+

The command line client will display help documentation if it is run with no arguments, the same information is also given in the command line client's manual page.

+

Version

+

Current JABAWS version is 1.1 release date 7 April 2011. Please consult the change log file for the breakdown of the changes.

+
+ + + + + +
+ +
+ + + +
+ + + +
+ + + diff --git a/website/images/VMware_booted.png b/website/images/VMware_booted.png new file mode 100644 index 0000000000000000000000000000000000000000..47401981f63d70d12d9e534e739457dad2f4d7a7 GIT binary patch literal 9498 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 TxJUiN3`k8$OR-$u>fOHqWt1Is literal 0 HcmV?d00001 diff --git a/website/images/VMware_copy_q.png b/website/images/VMware_copy_q.png new file mode 100644 index 0000000000000000000000000000000000000000..3da8b8135e2bec4c2c4249aef24bdf39bcd4a899 GIT binary patch literal 9230 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 S-v5h%AuFjUQ6^^e^}hhX&$mec literal 0 HcmV?d00001 diff --git a/website/images/VMware_cpu.png b/website/images/VMware_cpu.png new file mode 100644 index 0000000000000000000000000000000000000000..e1a7901e94c65b5b31563750d33727c1b984c195 GIT binary patch literal 33013 zcmZU)1z1#F)HXbXq?CgK(lvA=-5n#{-60K1rwky{&5$C}Ez*s&bT`r^A>Dk3=Xu`$ z{lDwm*EJl@oHKLwUVFv8?zJXdMM)M5<242d1j3S+lTrhL5W7Gi1WYtU;2l*{RC?fm z?kuP41_EJ%pI!){v`3ng#QMIGCf)G3>FwsEmZ`0e^Nx~j+_9Wm2 z2!Sw!_V;moifDoOATjS~iF}Zl3_@ULDnuRh1sP=W%iL@oq{0F+p$piW00m}V!F>=w z`iYb;5x&HMD8QDVq(C-;pwbbo&(a_rb`ZXmVi!MXmIcHvuWcm(XOJKF9_nyPp<-@}~(Y4sdEPHJzk5p!6>kpeF zCC*|X(CT~tu?J?h>eqpSD1i)31NyQ%uYKzLBpd0R*oL{e z&5ey&g)Rww(*bS22kTDbcI|unYk#4;%k$r@YcxTehC#B(SHC+4&!BlEBk|}kv&F3# z*}FQ-$2-yqsxEo61|3HHb=4Ox(NbxVr<{3I;S%u--L&J67Hccaw@4x@Z$OprL=b%9 zSPBizkuDVJaCP3duU&#bCrwTrlk{jvfi}UbBOZ@OqW7|2XhDHi^6@SpkdYJ(tHwaJ zXfGNFB=seTu~MA)tb>rb9fhRh*ivCads#J<`Z{#@CK5I~D%8{N3yCU+38OSuo3HE_FKi-8l%W@7%YcUJFO^|Rw+_b___H=l?U>RAnA5=9%K&*3R5z1IUT5u(yUw|1qlr|-aI-l zIucB^la4B(Q1J((5%0Q-(2SEKOh=BHdiq5Sm<`wGlVle!&5LkJPP&FzMER<38sjg< zWyT%VsCSu*(z)ecQz!J#TiAU^oWL3yH&k!dF8^6g4}jb3fw zodVG&?k4vpie)ONxMpse+EQVT2Hu+(J&CfMTD1z*utG5Rhcy17;8*gBd1YUdCSKbR z*j(CH?7VNpTS_8RN*UE2|FtW-ld^+!=J6aW^ks1GCu@45bV5`@Ya$QAid1Mm(L@AM zuLe6W$A0QI90%^Csl!;y==(Bm03%5u36ez2$fi+LoL{_LjH!95`AZ|F$VlCI5OL8f2X;-VACR&N2uBW4M=VA-o>`-a4i?Ox;F z;ilkR_PGv9^>Z4Oh3CVBLfvm%oP2oV z_86?wtUL5L^yETNAe0crw|j37)70KJP+-J^_Xi5YwIoLzi;T}>mJrNJBH}->*ncb>KRtclx3FDPB)b`72p*#C?zPBWKCQD zto&QsUt3g1RJl2evQS>@Q0r%EZAM^S*IoYeFrg*EuhB2+UKkZCY!17GRFBl(?T0JA zfR?~=+Hl69s9*P4@-CaT&Is8FTr#gD&OQ$$$P ziF=m%S~e8kpSu{YdXJxHrdOwT9uzKA9P%969)>Mu4{~QSWa)CbjsEPD{H?kaQ%R9AsUyP0eP`7N=b{Q(2eiQG987L?Ch@;+nlKvM$8C%(<*DC;|{1q$;Zx}_2S>FlG^EPrfiuSNt=?+fmWa`Ms6XN zg#)LsKnq83d|a%HL^0*tgj(x8>n$tyU!|5I-ygaiBkI`5l2H5Ys$)x^>9SzdO62co z=+VzGqJFow)V69H3LoH4F3DmVIvA`TScv7#ILdxJc+vS{HNG}4R8gCSRA;ND^d0|q zAs4R&jP;k#m_oHsN`>k_*D^XxDVH2*rHa!on2 z(QiAy`*9+{`eY$TG=1dJW_-tP%LBupsxHf1!Wl{XmJH5_`k)c9Ck?hR6#I6alc zFTB)p>g{ydeR;m}YRTV~?tb`J)0_w0VOg_sv+FgnE?f2y3Fgnw^J?QXQ^dLRTUBOY_@TCZ# zf3&%-I#(YpxJ@8RNO(j>NxHXUz+C)*2Gc>1Eyc&>qntj-#h znuQi8#xf4mCprG{)t7iwIIiCU^8&4z`L8~j&_r5%?ZUO3re-E@qr=A4A!~P=j`VOL zdDV+5XjfIeo>}#lou?@^GwbH?a&1N3P$j=ce@7PE)J7MEW{sxfv8l`D?3&7d$ES|7>-lcQnyqvF z$Z#gNh^%dX0=B7TpMVQCCtsT=v40oPAo2IwyyAfHkf3`z=6*8@X9c)nEpL8kBw2XG zZQ0ju>#B?BzsDP_=H-Hcdmr`!9uG?%?*+%`*#iEG+%Y|(Il+d33;w_g|AuopwZ3ut zt2T5hv>osmF!7(DynfmVhB^t~PnH#ABYuv>t^5U?o5t=9(j`N6{uvv10bc8p@(>LX zRY4E>6Q?BkLW{M7{!?J$PZz=oLc>BsLtD?~DsIpYDtybsxETL?*ksQb8>Q0bEa>H+czbHfBBx4!4aaJj{EhV z9&GVE3A*TgQ*_&Qdhqm;dxI#VCfHVMuA?N@I)Z%nxUn#`ca$BdyT@B#Z7S${HlrSP z_&8i=dOJ85!Cv6FB688o^%%R<88~;TACqWybM}lsGhjb%9Jn0k_vPnEz~$e`rtK9# zmgl@o&L=D0-;njE{m;l>E=Q5<0SiPw8q|vx;pTq-=+TN5K+{~{Fs=Aw^Fz3hMQW_$uf-K-q9 z{&d5u2?TE+T23os0G-t=U^>sO5z~ZpW)G-`)SL&jc&rZ9Sp^!suYLY|N0hOd*z2s0 zZX`Rav2YRIhJ)dn=8@4!K61ByKfr7s(8kI1co+f*t-&Q~`|)Dqy8klfh)A^l;?~|Y z4ub%&MQ^dp+~5O1LtF1eALwFHuCz~3euEhkRGJXrfn&be=&7+Z8yHWvO<3D!`{x{9 zqCTalX5Y3Q6wF@Lk(^B?#JG70>{rs#x1dKr3oN&vPGl3S=QYmbg$z7p12rI4!$yzJA+4l9D~ZFS&%c<=e|ZlGXa$M;=KOO81>B z5=AyqDWKAFYY~!RJ{)XdVswf{jS_`5M*O)rUGWprY@uOO zxJSE4;$_?#F1$C7e&!+aod4nCz&xygtt6&&hHp=|Nc(jgNB_09wFpAvm!*CmGCt3( z!3>KRB}R!MPlG|uQi2*ok2cyFl>+QaGIE*$7`*^KgG8ed889`AwN6>>JcbQG=v>?7 zauvdjn8fZV1FaVyGo1th-!)>8DPnvpO72_fv=Rr% z%0ju9;jYO20(kcK(>gMSj!NhL;T@O&(a$K1%dp2zzhJI7=52xso=$CEzgCp>Ukv0K zbXugcez*i8jW?G#Y|@U2U979uKbJy@Kdk1Kn3$gw$!s&d_q;g?i7D3#c_r0dDfDIWiPwy(X6W5I_kNl=KWfA{Jm_fZAVqmlAYmrusCeI=Wl9ZoF z)jZ#x_-61YUxEG+VDU#U8rEipvB`1fEd5B0LLVV_^qe(C^i1;3rbLqtFd{}G z*SCLZ@T0O)=YXYP2=W>}nhJY&6ng_JhW3r!z1T3F9RA=na{qTwly#72vtT>sK}U%= zd-|~Nd>`1n;$X2lCtkes%A2X|p|^x)nkDIBMKN ztIKAT2}oqIKh%n-I+I)pKH&1McpK`h@aTD z1C%?k2ds`zEAkjVSeR2HTRjBqGcc3KhgDiax;qN0Y$fAu`kvMt~O`t7wmCQO8;|D>s~JN zndJx|D1%go(58;TZ&*GfNT@66b|s~oO>IJN0KMjF`NnX5t!(n41dm{+G_$g{LMT>% z?NG><@&R{z;Wuy>t*prPptCK4VF~X~?c%@1a%nFQkBm!Q57^JAw?*gbj{2Z2bNk^! zE(4Ephqn>h#3vbbM}7n%Q$69nxFwDT=XXI>K~7j#DT5hJRN24!twV8?jURrv%f4u$ zQ+gws*0i*LYxNZF;y5%o@%m}ZuDSqtu*nC+{-OOkDgY43vC^{v+jNnh&Emn*`xsIp zjXGUHKD4CO)WK+6yP8rlv{D~jfFY@hm58pv6q4k&JHQ*TKJ06&L8d3He~rgnv+cAP zbc$MlaIXF)QBtrA2p^Iclk>`1!o;m=2U>$G_22;O$%%UQg+Cuk0S}(q<|5nD2t2Mt zPc?<9e=Z{B@!IPj=j>`;?L}HjCqGQyCv}xrd*sJ^V!s;k&0q2#)Cc|QWvC7j8Uah# zK!FIE#z`4=A~ezfz_zjl4=2B>$&dw)ls3<{-+U&d*}yXna+Tn9jw?y~Gcj9^cERn7 zNT;7yRxb=^NqGd6#M4%RRZn@LJ+P3lNg{X1+5X+K{^g3e;C0mreBD&FTFRL7LyX`9 zvitspVXB}wUN}E;WYGr@)>dxA!YY%dbQ-XNpXURQ7kfAa`{er@>ctCPPr?6)-00@V z^oO501>P$rIXI3vqhMBc?+h{=s%Dodx`hu9nLez3Z#GnZ8M~a@do22_0GI$U;`j^c zdHO*0?~jfb0W8eSH&V0KRQyH@9KNU3mV~{hLe|$MS~SVAI@dRcn>Y_gA#?eSewKMl zdaJ*p=HXm!1Xk(4jQ>t!REz|0x?QZvy46XpAKRVhpCJWeqm5ZrW3&3>{^e_PHZS(x z1s3q|`#$GuukTUB_c4zlXFi$)Cb3nO`69Zca{6A1?>m zj!(49+=|ZQx zR@^-T#(7@P<=dd@1AvLT9}8F0+cPCx*;ht@C$`}=F#57jRSzF0M;z92|3pf+CJy5* zFa421+*JHcTR2*D=KJIDT(uN?EwmOY)yf%P6I7L3dcXTZ~+rm6oAf?oG@=w&|+ z-zb&12yp1FBmu-#u+&5PWwtGG0Rg4< zekk5qI3dfHPFzzTSmqO>eykA8`@`PVF|UNi;iq7{v(q3EcEmr3% z-yqd2=)|K((RbZ3`Lx!W6H*fN{1qC>N#y7uvP^XC!B^=aycC_{b-zs1r?2kAOvUBu zuFMTRi!w=cjK^Gk3UvBJs;7K8kt*K4YtKhN;`52P$V6`ev2M;ve;z_=mFFh^VJiXd zru_={W#=;4Qyx@{wdCkmb+%^blyCBat@UE7j4c^<^3@}4X#dr#A{8f|3N~KfUV>c% zv!lo-pO-J?Q7U^}akD}Xq(9A<52Yd9^9V^pfIc!apP&E$!|yiw2{S#7Z|#b*bO1~$ zpGyBP6M4mOyp#J(5%Q0<0)OEDB}|nTo&Sw^^nWuR%>TXV|GmphF*e+)+DOo2XY2H_ zwOd8dqj0X-k-Y7nK-qm0A8vIjz>e;;6{i0@>csP4k@EKHp9wNg8^TlBq8x=G2*4rB zx9J90weyf6p8g% z!xYG_T&s`dGu0gXVYJ|X1bR&iPIN6|1;JzWd0IKeD`$WICrGN80hmqVrTqfWq%CUx zGwY94d+WnG4KC%s`PzwLHe}>(7QDR-8eZ#Hsa$G$Fpd)GUIr~9aO8IxuSKHF!Wm^c zBBEieo4&F5gz)R}!T^Qtz2XGno)3K14Qv^~|2;h!`b`@mcdsYundmH$YIa*V(4WPH z0PSSZVmNQ=kc}6+A{B6zuGxu9e03kk5J9AyMM%l)8~++^Q|A1#P;0*0VL{H;<(g?( zZ`HGyotyhdz-OB!4LMG{32T=B)?pTr5T0}RYLkodS>)b&^kdN$P0oY%L(scC0I<8C z)KPEdD>Gw5F?;whp_DDMWSKT-$|<~G`?`Q4P&>g90SRgv1B7vk4ZQCveE=TDt3#tn0=ex*MGe~V3-Idfeq<9Q+emm%A` za8?C;#vMT4jmMzhOv^KW#E(-KvHr+~U=>HsR~0joDQr;ip~{zua5i>hz-P@mg}Agk(WBHZoY#={?~f!eLGT_zF$sW z*xnwa5@pt(u>El&e>yPZ_yG|{gXw;4D)c|uH(bDDrx7A`zxlTpN%FP64$et*{>%*ICX+2tNMW{cjK7wBv*?$_#`k@4%A$gy#by~zylUm_sm=5)C| zETU^`@H=Yy9;^Vli%IM-jo?8mP9pQ@0XFh@itzPojB29)tpB7CDmR7j9uci+M-9^0 zAeT}>d$}1FH%?_umW!W(jt%wLB`S%2o`Lk7HN=%G3%Yn`uiGe_m@bj|Yx9g80-pMc zWIa@f#Qcf*WZ^BohP zOP+vcm+g%LOg(o*SEz=pNE5@qJnkUZn<}x@P7VKLGcK7?E(xC8FCYijt89$IFQta@ zVTHihryB5J|M`++8gL0s&E(xnvM&T18Uau#eC#YH z)PzzS47!&8cwDLi3$tqco8p-^jP=Qcl{3w#mLtXm<&vDrXmxs)FW&bhK;#enSeTRZ z1o&!WgkexQ(Zv+Lq2g<<@9%L2KZ;;5?C`)Fw(48Qv6Rmh!4kl z3ju&R7)bDdi$1jux7{UC-SP8|NnRX zi#Ku~uaX@6`;pE6mk!jjV|!Sg?VcM*>w|53>8C2w3??Q?qOESCUX*;7aX#DxH~2Aa z?cJMjm~h4|+}bcCN=t~9=|$YN`){+H1R^AaFS3fT=krUIll}eTY3;Z@nGun~k1Wwe zB}&K+ulzM+K&dVIlF7UrufeZ>>!QqNSEJlyh{U}CPSy}_igF%0bdZszKQ}JovQK5+ zFSTMpmHke%hdX;EYfpZnHvQt^Ob0kx>PPvO2fXc`?a?j;1=m_W*GO zkmLXSV^70r>IZ~o^h#UFGL|_iCoh{)(g{W|Pk9H`#HdO--ndo!5A?}0PSd1t1dDd& z)|2QEX_2_$I#Ie>!gTKdCgGtBIYccjg9@8ym_?_Sb~Q^_+0}sHu8|ji(VK*Xyy~G5 zyO$KiLma8kQ^g?c0Afi;8`?Ur0rg1&2Bm zy1J<$bvK5}5uU;;6DF)W(w&CTDF65oqQT`ZJ3qs*(Z%yxQhJpayHcs3J1c4JbUfx| z@IU=hN)i@s@rKlNx+1*xRJ0`kLCP6N3YVkX>U{|HXJlz!NpD)mX=`3gNN;QUOGjWT?fvEjeK#4G0sX zK*gU|vFNxs-{6v;5kC4vhTmjwXSQVX!cZTReEPkFQ;||-AE#l%i7E^q+R-pSy%?Z3 zjpS?yad)ysi&4!fhKNB1-gW@sDJ1MG3~%rUCcp%+M{i`hp{>8UeFQ1IW9s?TZaMju;AX8ZeBV(Sck+ zs#OVZLzaDRWo2{nI*MAcPNeN{fh~~LSv)I|scxcl*@57~U`<2qkAqXfPRi@+Ok1`t63fi}=XkkMbKT$l&ypB}m!)d-;;u<~OKDA}E|D*gXi`8 zJc}@CThO31AEg zt`x+sS~n?TU&t(##!pinPBiez`fJ>7uQ#L|?5Y+{eS4&A`Q5A?!L4!t)`({neXmYK zfx&1y>b^UuF9vz_1T(+CFHiE<@Z|L-`9-D{htA(&7xTQY>%|M$o`nRhSA2wAwMM+i zH-9WX1PP57uLESWJzhlZlx~XS3?Oi2&d%O`m-TH)(luh)p}LaL*gY@{26+H zaG)Jy_JtKZv`?yWQlLc(#Q=FgiVvPd1Fp0=mSjx)GW6+(wjcrEhVUh9GJm~YshL2n zw+^lCTX!d=RfFs~JE^D%LTQRLuy|$EINk^&8$VdPORZ#e34)7UFeC`9D&HP6sUp`Ci=%n7B8j%LPCU z0Dx!n?FXSyjgI9O_`dcK$8`k4!9)K2NsH`zRMpi{pbau;?k1OM(Jgc^P>;nQ=ua-otO2?U(Z|T z7?A2B_(=i;E%W7*u~Yu={a^C@(;4`}953|a?nh`=Z>`%csL+!X6P1X$@Q;Q-WC4Ei z)0rGi7YZEFv|#ijmO{i-3MtBtF-9Uq27L*C-bOug{?`)ts}z$7FNW!Jm$rFgM~$n! zASba~ebc$~oNCQ@in>aiCa)>M@)jSX6d=s@4$%l-sa1+rh4M+*XV`{))U9p5C2oJS z`JhzF&oBQw6V>upB&R8+pDt%r)fX%JIl|o^6CqZcru|uAcdFO&1#zgHY3y4j)ou_j z`4SZH>vyJA9~5INvIlLrz&fH6LTqzxY9oW6kn#~Msrcdb*K^-Px*?sLCE7EHyMgd% z=tjqj3@}^NA2u#JMR)2HIBLIhZox#WXOWd@RX9M%&((-Ag7>Yfe|X*V_&<RT0--X&LZ|v1;7R6q8Lm0j_ zJ6gkUU(Mo#HAu2w$5}a*!5i}6rKe{Iv14+Bcdj0s6VoztZAt?oc%Y&ce? zlHlT&(<1-1dkq0_tg4Q4&<})utJc*U>0$wM!SBz&wl>42V2S4U?-5B-)ea5~TfNVL z@1x)V7|KoB5vlkUwGC~rhn`HJs*Im4$|J}mlGfz6XmfI@;ypGU}j{^Im9 zXIDB@Cxm~v=g|Kbwv`OL7;n$^hLOahBUwdn$d~+ZKRGB)W$@+_&B%OtdqL{81@D&( zTlNMH0QIkZTe&)Pr!t6dEFfS?N3+2522KH+n>C8w#A2}sl-=*k>iC3)t z0ehyZLey@d830qVZ!CN=dU%xSzyAxMc;x=nU$#y-`8C+h1UHd;{{d(XFh-t+ootbQ ztrIyDZ%Ae%r_Gd^Hu}qhVafZ;&{!%{b(WYl{E}6K_3R=oWaM|H_5z%7X74JXT7crw z`&c7Vr`Tq+>Tp)MbDFXrG5|&iA02%!0ygkGYQ9WPW%vwV+pTN$1?uz)5XOX;Dv;k| z^Icp(<<>+mP+V~k|EGGI!@dF}!z{_IqajvESp=S*et)kA?rtO3Z8BpG=%aI?QQHj(Iv~P}7K`BDU%f8eA z;PulzHw3QQ-&>0d35?;k?qO%%!<89gg#qSbsi}$1Ef`={2j$VLr*N@U=?RL8Zj8S&| z9DPhoc0I$k=a31`L>3Qmkz0;UqAB7;KK*YJ0LUYFWNX>Bv({#AEm!T6Y2xFIUb!1LM)Bb=dx-ycW4f}JQwl(+%zHNJxNbka!_VNI z^$E)D+j7zV1NVt+0y;K!akU_>@k)aI6}FOmCK!}T%7!qTXzMKaV$HrdC^j6h(Jlt? zTLd8!Kmmdz+q)*{V{ksy5ps5fpt5~;RflOW#D6NZkjP}Ft?Em+qKCy|13X0T-*6)f zL`Urn*}o${ep!Ev7_!;YnUN5jFE!>fLO~Qq17kfpT?-c^a`pVx5P!M6#u7NXeSBsq zzq`=|wpB~C66b@x)5p?(q4{VqJC6R%Vs-s6n+lnWuM0qVo0OeD-BF6{hTB|qyoTAw zitn!4e|%be;c_Ch=G~NQl>V3QclNz z0!pp_L6HXD7mRcSiP-YIAHtvqo10t8L);I%oqJm@4;DP6WZayWKc{+{xH4*qQ^r~# z<};;w)_-D`kzxe@wJ`Ip8VV_Z^K7IGj0~rqp!E1icd>_S0^5;{?_@ofik-UaKgf_6 zey{#b?>&IM4F{yG&)Z10uZvOz zXfU~}tg!|3lT3q(V`!b&_FphBKR8l4UEHrk9Q26HcS*P}5Oh2zV>B6L+hOCJbyC!^ zi9hgm*q6E+U<%(kU>{(Wey-rB1Z!`-+9q%`fa}9V-4}hxK|C^!LBsJ-IjiIZzG*lQX$X}N`le$>(j!~JR`dZ28siV$VW z6(%5&E7TgE|Kr@I_y;%_+QkKktLQMW2se620>WANn$Zt(p^TR#Ss0M`Dt4tU9SV?q z?1;WqcwY~AlJBSqU#+?mBW)8hu&fm!R^r0snxZsM4E4lT>sEo{+W}i|(8`xu#ippF zb@%fb>@hnXuPE1ccjBM?yaM4rgUP>tk8^XHVmYQwq*HfvAEOu+PTkThL!|tSmt?)* z<$NRk45x77tw_pf>-P+d?$k290u3LeUo$33z$&r^Xvzm!j7oSlFDM?T`D6iqd5Dnk zcAOE2LX)jsK+&lAq&ER*Y&swkCG2VSlchki`ZfYx%)1) z%}rrbyHREQmcgSfNh-Dh!6pfbty*N3f!ECMy;p{B(9v03Bdok=QhyIiMI-(r(#zj~qZv))M8%OM{vFW}T+3f~#vQ8i7quGdH+jUTObo(zseLLPmp|MO zQ(7X{qLyf~n!pax7?d|jTqQnsiDX1LMkEb?FsV3xRg_jJrO-kWK)srFg|J|1Ug=bj zF4WRKEJ4Kn{5<0x!B38=4o>w8mUg(L-hX<#=f z(Hoe|FnPj4e|uHi8f+{o&)fpz)_kQFLH!LZt?tt(8aZ@qf>*sIY)^(|N>iX>WavW$r=nio{4-ptsjsKU z2_wL_;YyftQhFfJAsxRQO+-(f3Y0H___8pBh%#_?G_8Qf`XDBq0G6Rq=3;K=A>tda&LxT<}k^zFO@pm{w<6n?Z&o3J}f=rtT!2IXCTxeYI z!&KeUPInEaAbHg!vCd9;Pm&_+3x(wFR1*ytOUys>o__nG9p*S9#6{#aT$7-DO&96s z0BNS(f=C%v&|o+-*ZX=Q{$20$nc5d}*)Cnn<$uAtePX`#i4y!5?H0O0V>@N_d26;= zpzW-@a;Wy48eHTDfgSV7{r!zZk1q-;07_o;J=UEgm!k)PPZ+HD8Sae@M0)40p6g=S zfY|gSZq%ewW3PDeI|&BOtxm^aJ?lKOSab#SX`fsH&y7=i z!Bq)Dzqva|66`1F%!+(zz-qwi{XTXKqjS>?9X$n8g8$N5y(6_^yQI<1WYSu~Ss5+H zCFXqE_Wl9t{3-)y-Mce@c9GlJ@wh{{<6JRfXL_#O@0-UKnKhX?m7`*%p)>1E0KGh0huLLnIf2%J|Az&+X7)R&bXGbj!z>nAdTpU zm)(~v?n9ZGr*V)d!RT*;?4Wuz?mPRG672m{#x$MCAquXrTz;N6TJn4{L?-veLH}US zF{VE}NESyYwve=7+(t&T)&ZbUbH5G`I79pb{Zf4eyZj6tzM1%n9o@56?FE+ zh8<9rLDGP@t_9kDLB7`e${#5I2Z)w~_#UEXsi_PiKW=>rwLS)r`=9Xl)BWkPs*>+V zri^^C%=VoQEK{s&^=Pz=mc+>!NDI~vhY~WJg`gY1M1p|tW%z&fgk0|J4gmg>%>Sez zqB^Oq+5h`osc}XbcRG-XY3-e6-`!}(2;FVC9cxyC)4R9cxLK&|*l{U&66a)WX<4$% zFSlP)f@k*LzA3Ua4j5!xWIyCG?HV){gUcDdIRk1!Z4Xn_%Y!&8UPoodk9%>lF#9bzZ!=qhovSv8m^^mY8`u_{IICh$Y|=H4pmj6h3=G6%?mCEhk{HZuHs< z0tQ6IA`l&|9tM7f>c*uKeX zTIAEN2zWWo1GJA^>a`TPCkJN(ccwkyEx+)>=Yxx8U55$5kE7FHJ5Q-J&c}zJyR{E` z8u6~dQ-xjEUVp8EQ!Y#|TC_VTk+5Uo-zdmJ>W>}$YnhY60bKhEg&yq8{1&d#@GLg` z<2r##a&;y?`!M-^mFR@W&9BY#=z^8NVdac>!)%MO0W(S>w6Z0cf@eU(pMl_Y;yV5$ z%bqH*sqLx?m~z5!t5a{!-k~8Hff%u6CPm0}IMjkU@3krf&>Ma{6Yk5FoE%D)k``%K z_8y=?_oKls(DQI20a256D;($oe=qr=r9P zy9g>)cPbn3CsJt;w$+yIB!pEeQGH*MDZV!<6UcGo_4_xpMK}AA=7D}SA&9iD=MLji zmXk*jqD2d&W&4I7eNP3z8#z|vGW2>_7M+kd#U-Fi*dqQ!h+f}nkOWAqG_%8n*HNEZ zSa3oEAhyUL{D{gCn4aW|EqjNDWbks$6g?vJA}yl^C z8(12eB#Mx=ei*LN{HRJiZ6qP-$(Inqpq^RaIn0!DOMC>9l9DLvSts$gIJ@IHUe(N-lbxK0x%rMU%#w0AOlf>QctO`rgTaJ{-d zrU<78lzo*h`}Vwo43A4%&hQ+_4ms2px%@}duUE7F0-3QNBWGGJ0sPYsgT5Ax%MeyB zS)1H0psieU1Z|O8hOW3RfGQlGJEM~RS_{4t0j0T)vMGdW#cw2&Qk?wGb!4>FyvUGO zOeE8S*q^WaC!xzvo*d_u0e4hpU}>bA1C#-fex3qzIJNSx2jak9n^`^@bPX`;=CBcf zLkGIn)kxWqTv`_pz#A~{`!lW)=*>fXX4G$L-TQlR@z@5?Hr=W3O_q0S(J5Gb(`yy8 zTWMi-kKwl|{x}jWXVQhBUY%AnfIRs+X-d{Xu@FiDMceG^O5u^`9O&qTq6|*f@Yf%o zhifZq``?$y{(dTDs^5D&^pIYmpXEXOK2*Oi1G;iZcR#H5n!WcB5%ME45ZqLD%wPXg z=dHwrreqYLOtJ9UPq{tCB0#O>tOWXFVOC>N{i35VotgVb zg;j!*p1m4p5T5)tSCuJ-ry~RI;ByN7OM)RJloP1U3Q(Q8(S$tj*#dZ@--G%upDL0T zx;qi(Qa92U@+Fb&Fs>kk)DP{6@+Hi0oe0j=#=gX1i*KXa@n{za3FxrnVxY=NHB!UR zBQ4-S-KU6t@^D~a7orK7W=W%_8-NAbMBDel9BLhUw0t*7d!#Yo0zTR3)WgVg)ZsBR z?Qty|VDJ!73mmY)hOO4Yh2iYr*9vpRgzvd!5fgG~!L^&oQ0J{YOsu67vUQmk?1Tt; z%;xX4-75#WK#Az`XIM6#+;*vd;c~8hMiy&8qdmZEnH}%#e!gd1s4W5l6nDRql%(Z% zHF)W_<3%XeN1*6;#AVtO#%jlzBfQur1om(Cu6h?xAfJd%^w)xlUm+izcXcyiBcesM zPpaCh1t|TI8yB-sBIt-|bOS$#_^B*1)9i1T*-CDfzXQ}Q*6qkYSH0_S!G>0Jo=QJ) z9ku7T=UNfNKnZ9w-_X&Xh6@#J3(@WTP1jPBgbvn28zv(z=0V+ng9=wKYrC1iC{fr% z1tlk3TC~UDOCGuLVxZZ^*!N(_ow&(BP6Q#*?3xMN*KDPgnr@|hz{%Hh_!U?8l!j8vl=G?k z2aqX{CUG8e95xt$xRU@eYieeUZrM{#M?itT7{S37FJJrfO@AuR91`ps!R}%Ma*c># zpopi9Ty0zF4XAz3z=xBdM$8>tXQ?DHnn^h|O!kojuLepXN?0>8!{_#fjvA?Awssz% zdE%gWliv+sw(Pv}iDRKA(2pAS;c=*R;?(SBTYW~Ds?>s1eh~Y8WB8|I*?trm62JIT zuV!&sw^DySQ%;2M$n@9`yseT9+(}O&tH>&Ee5wzE1>f#J6?E}fPp#OCxg^!P_!S)2DEJ4))GxY;75BEdfv@&X(gC}=U3I_iLylUAC4RniWP>Pf5Zi+8*AT<1+BmH;8Y{s zwWP$jTv71f>egPSOm)Bjh{%qWX;zlx7NpE%y0;}mruqVw5)W$Z5F%>%hr*y>t|~?z z*oYL63huq;Z9VYc;n0K=?m4c`X)7t+d~Wa=j-Ue<^WdVPa7kOgH*4iC9&#UDJwDqc zG!z$1p5&Q4;NWrurcv!=@==1&yJlbIUh=nHUj=Dcm} zPePA^0_`TNVrc~uP)%c7a#ie&?6yOZxpb)1;R_eTCri+sxt^Wz6hJ*lffgz&T*7~w zMZo!i`p+d6^*i4SP)ZTA=?ar-#7wKntHVcGunXn7n98Tm(gJrK@H)6nd4&F5q^&{so4?VXqp)>=b>?NvY34iw}m@>L49+9#TOLiz> z1eY&dn7e&fei`wcqJL&^0gZ@Vxz%t9V2DKtABgU5gIBW;=Fh*}7@w>288ma|40r%l zsJH>xyRwy5zdscP*yrg#6lC0_@(tB&KM&B=k3Pd0+Ek$?kIR;E)EKEv!R-FcjV_Gm zDmN*GIce)MVmNYlXOWXp;ePS-4jZkD4D<&%$f;i;80?zj1w zjO~@!=RzeKH8=aK%wjZA!dUWBAc2M&ZI!l}I6VzY^EYDJgkt0eI#*awsysM@!N;aU zJZ_BS-M_LRynVL7V+EKpwfrc&PJG;UyG+{K{CTtPlIu@6KbqodloQoAIp z+Z&*7f{kLY(I!(%bj})!H^G|fb~Z!DvXe7hLj?R#LE-Z?TVmcoFurmFXd$BU&q)Sc zpFU@tWAcIJ$)%9f(QpI6S-zwLi9b%icV`8D5EfePRyE*R7ZFH*&{BGF^h}uN|5WwX zQBi$i`?oYh!yuBFPr#btjj1c+L|v591~8WuugdHJO20M?bPZH`gkP z-dq*3<&=;#-Wb~OVYf6ge%-^Au=?lY2NoydCi(U2Fa?)Shl@b4k{u+(IFwJ0t%WoapfyLq=$%igkpC(0A+hDMVA05bsaU@U{6Byj0| z)#@eT%wr0PzwVw2A>k+)DWc^j&N#MJ1f1GIx5odEumNVY-94MYgYLbhhx7C8w~T!b zKFgYWpVjI6S8ix{0rsYQ@gj>BMX3|+ToPGaY7nRxbkO}5@F8n=S5eX4^49U2V_`&eTK>q)mnKYUr8A&z4Evn zU|X>+y7@S#iP(W~L@gZu0trF8Cb3ak)q9WbXqV_OYaHUP{8z&QhuUZ05&)$h-Y10j z-+`yvIsgb09`)q=HJhg!%lQF-%Y`vJAam)BpHJR|55`5CU?5rfx|D7Z2&#b(`f6K@ zs{>11%zhJ4Li|w5IOGU%_I+@3p9VGv)9kOULb)0uVnMt-{VQwf!9JU*0chfK!YB|4kERJa6#ud8JaBOhd@$HK=B$f4LD z6)p0ILVF?=iwD=rm5O7BiA%e*Nf;#BZQMHPb^@+Fl-dp=NPAP*uYG13=;95t5yNby z=l1R(tO?>>Hz4mySPsX zyI9i{1^od0EAA|%fjddMb}dR<`3qUYo*4H_EMSDg38qCZ`;6+Qbe@FWM#zZN@Rv+! z+(h$)R{_ar*H7J}{TMr-_VGKzO+}o2LIwG^^|42s!Dyye_Bmz5p6oUu!Z<-05-P&R z?(djkg%_w-Ht_2Syh=Nbfq!ea_by%^I}i=2bta-OgW0&TZ#%hum4A_3d-tg4*OE7x ziS{~if*-Q-fp_*vOW*Fp14KP0rhM)h*UcMTI)c3R&mlt4{5M*2wri?XA6ZXt3{JKF48PCW=4E9--c@h9r{Dos_JCOz~092p+6 zr1j*_vjxsneYi;K1Db_q;R0w0VmPTT@s)KzJAMM?C~bntrwn^#wB6~ez(psFGi*X6 zr8Bkke_Cuyx((Dd-g0#dy6WG&=n{b-V%hiSvh8f&hPu-LiF>6- zB^;{#ODxb*7@AGzh1GX8mkcn}fe+>=k*Nid#xi4_D=Yk8)p7I|G-3p|m(6*hNb=ui zv*Lm5R_FEaGU;|TjUUWp9hBGdLp=nb%=E9?T#S>Q2L-6oxeOSj0M{&bP3)S|?GO`T zsIFG{pR5Yd7{jk!4?$h>{;8K94p6>T>JQyThOvLOL{(^-#8EHv+P==#nVv>Z+t&kr zI)raHbv~z;hgrddR8nEP>gdsp*x~lo8z*r$m3+tzyiG*>l*xiRU-O8Dwwi@RtV%hW zI+x6SPRkm8MVIJbyfiDueMEP=FxqHTuXf!Ew34rCeUz^Vu|r22X7Ws`IXBLX=HvX5 zBxrK_fy*ll9QhC8pW#%6p?P7xw7mi;0S3PH)AYjFtydBUHZ=$_^KZ-!$rsXyJLgjd zj@;(DDV_FTJCz;P&F)?lJOcM3 zf4WF7dz&+x>B0W^L|00=ri$d2^9ilXl)knfH`Zk?PAZ_^d;=7dl3$)6%{jz;ZdxFU z2Qp%+TdM@v&B(t*z#I#ZbJW`=8Zq(>Lu^&s==ED|bup+KCiy2{(eaRq&&AM<=c_3A zh~P$)E74fZ$V0Ge$=!LbV)6~l0te?3|FY5QD{g8b*RVDb;Y!8>Sypat9xhe&}iUxJd3Yi{Ia&wNQL;mF#bbPV&Gi#f*I{+!rOAyEAf_>7=Y8Tw7pt!&aMfAhCWpfp|CiXmU;VKRhu(u&5w2|F`3pgAW^Swv7VhcZ ze!#$RCr07#U2+)lTPEW5x5Av<3*PJcH$|f}s??e3qa~Psvs}#vv>W+v6Q_RWtBnS( zlxfRX=+r1Qu~Q7pkBy$eGaXoWZXr)bl$MyXC__yZdV7c4_~W{Qxzze;0y~c=O3@l3N2uF1}Ja zcVGm=2?g8msDUPF*2faNpl?(kpcAm1(z(y?wUT~0-|@+}5|@JD$VH&{uAYPxF6|8y z4@$+1nmRWkZcWdKKNoqweJ)kkjhLTG?QbEZw|pb1@yIfms5s?$qVT$i$bN9ADAY61 zl&ClIM@0uHx!$OQ3BA=oY$$a9vnxt}Isp*T8~(;*g><__^Tcc$6kX0FUzq zPacg46Nups#fwhBaLk^)1 zJ<=a8G>4Dls6HmI2f~IXmR=;T$T|d_CCCJ5i6@8LRw4q{ZOQ4~gBO7Wl}RqCaY++k zj*)W%^EN9kxw-Vt^_5%m(JDBtYvU5ixZ9Apc&V_@gu^*e@j1~y0SVd{kzhhSuDG78 zgSu;O4#Q}JQfwM{5-brZ$tY%&iVGIShns(sXuPE>4DAsG1Q$Wp*k$-r0HK_MVhC?i zuKP==`Y%3im?~PxgzU}4jgqsopaJ7CM(0_gnnx{Hp46#7bo~mRVMJe4%CyJsbiCZD zGLD9b*3k4N=4yC0iuhl`XLH8T54aSFDQ+w14=|Lcx|Tc)?tp!M@Z4BouJ2-)Z7hwEH1v)J2S$C_a8@ z{vHQuBn%hk4vt>h=plR+vCIx+5a6lb2awkHe@C-mGKcxp0icZeMv<=8Yni!aCG}vX zUlwC%GtnJCrYdKZAWg${xV&UX0gPKrO6m!!=XK>XI+`C_R$VgDLxbG~a%D$EEAB;s zHl{EhRlyb!3cD71XP%=2cQN{fnnE5aDO=np%my9)>LGgHBvW4Ay-BieDNlvk@4rF? zn8&`q%+yE!ab$gm$&zwE&T=zAQiL^P8ffDv@=SupYt-Y}vPSaugoXA?w9ue-!*%&t z<)kjp%c4q;I;yIcTR+HmrF$_X*02jhnPdMTs=|a|^%QfjvY77$-x*#m@c%kz?0H!uB*TFX+wL|8vpmoqv|wo1 z`#s%cS38?)srGeGR79YVDNvr*nn%}$w^H8{_x{^T(B!~m7fQyRF6NH<*mOfCS>Thh z*T&e&C{Yr%HnH<*T)Y8HIg?z5PWXn|Fh+>8GWD($8=6xIXs3MBr>_$YbKiot$;b6) zxGF0KwsDo2flyb^ENLguX1AQjmh%R9=%*?`jc_4hN7TC4%qAsO{$_vOdkC99U-I;J z?z_3zY6}Dvnr}R{lf)AY`!`3fvtXU?!Anu-1IgmZEco*jbl(~3R|P6CFnTY|nk{}4 zp6tpq{3cES3f3B6^X|Uft5});W6&dR>xB|;jk%k-*m{bW3i4%w21l?d3|HoN+cd&q zRF#UKyM%s>U^gh@?*-5?1bdH@0+mUUCR-c%DJ&&Em<>=_vVV_Sfa`m|kmtN&=wX*S z#)7Il+^ekl74}APgBN9Td{+ukqY#zmYN)b_a#1vY5KOt%NZBW1pM|3 z#zn=P`fdd7sx~Y$nK|-w;o<97o%)@aBK=$%9{cjt4Ip0kb!E#$9ErV~`f-M^5y9Nw%gMSJy7_*7D z=z93B%jE6>An5A`p%dhsKsy-Nc{9@U6IbKn8!@63ffyO%CLOPO4p#5nlLiLG3Y z;u7g`jLGW=oNQ{pMkpJ1{_!uz^Yh6_IbgqlLwbNM+pvIWi1;ubSp31PIu`ist0Tzo zo|U%$i}Wo@ z6>gdx+`ngF-sm5Y0=X1>S@1#oV+P7o&Y93D)iG1=#OXR0VpHr26eoHXyuZLYg5@X9 z{Xt5x_9igUF_BV`3mOr_WDZsv|5Cix{X>c3Qm4D=dm(rmzzJGci#?l(w|roGpw(s5 zLOHPP>!Q5i+K&-6KHb9y=|877yH6NNBy^d|N zBjX?H9L6q?1u`nBwj!RXAc~hO>xB1jiy7;v7(&!Dq4Zce!nz1K4s<$ko!l7Z=t}vEWh#N!d2-_(7Bi(6yLdK zDh(-wv>%!ZeC8{l^EaYZ(n<_hGwVN=Q@^pnYE}2SCCB=W2DlWLy)CP=T(Q^}ck}st z7q;EqYaflQvL-&=$vhm~j6$LJDBbypVEmT6unAECAYk3Pw@7LZGc#KNq;LNN!O~@o zxJ?Y4`s(G6FJHh2eIIX8DL?twRQN2N$(gm{+DZw?_wB$ zjRpLtrp{gemw~jY+~FgL#!LP7>&a4m^XI3a{*~xO#+jx=oF^#%N|aV--k;o(aCydu z2Bix?6RFE?a^o=DW*_+}lAJP8m|7K4qpJJ@Ms7kMvo&`Gr?TeC`%rq97otU|GV%?K z+q14SC!0A!uVaH0?0Mhq6{U@9Ja$8Zht<~Frd@Fpg52P~Z+b@dUXAzAon@=WS_IDfMNsfz?;s9*TD6H0f%Lx(h! zA7W|s{rfkoL0S>0Lm?o)Um>PnM~VQ@d24R$Ue8#{GgL?cnHg1vvYQkk8o#1d+Sq;A zDEqr=U{9fLIDUE;UGli_ITbZ^tJDbKLVX{ncRP#|7+Wi6F(qr5HCvidvc>!Lr1NUo z4Nz}M;sx$Wbz9{ASL2*^fkx{-w$6CG7Gjir{Y`QB^a>s6-NZUwX{^;iM6Txc=9r^)RZ!1GzOT3fRVIeAwqYgM)R zcW8et6OHxliEhQ1t&o5PD~(o)Vams?^4H%_Y9rWS+`U(c#}rRr&+y3vLt|o%MrMSd z7q?IlZ5Z=lQQDN7MY|YaA~b-P?#>z+l@k$2m{P z)r|5&r0B&E2_lLVRKeTCN@NjkKLb{dE4~h-tcMkR^C$30P+!L6uHN@fe|WSve-hJ@ zBTVY~EYrY~!uiX{(if0u2f&-d@8G0J^lO1fUKf$V=Yv)2D+^^)$I_lGCv-@y_A#0;Uu!WWA3PvXjILO@ zAWB01Ppj+gz|Uj!c>!F4I?jY$X{@*{1`eoN)PUP{xnc;3kvc0y*o7QnVZ1jKU8dUM z#b$_0{;K@1xRLDiPs;=2U5I=AS-L~E{(P6|-|74Ja3l8|A7nW`? zdq|5qyF`#Xed-`aQG?tm0iYN9GYNj#5nyem>jlohn+ft`tI#}wQDx^E{EdULKi{8h#y*46qTanpkB=M%(N9|4b#-|@cSib8 zOO^E9$_z_ok3AP*vHB$SEAMwpt+lU3P zvQ$VyMCR%!6UR%whS9(PSVZT&&8=H;YNhuzM1D*2d&zK=Rw!i&n7~riqF$hpL9|9J z8ri7Ib2Y^+B)NDj;|z@AwcXrdFv|>%hv0o-1qt$OmR)A>g;z==Bz?L%c1xx5`qQ3`D-! zC_I&&5(3VaAf?1C{NE=)79Q`*9|3nyBXDGZqA>dcR2z6cQ7V5@%^#-XE`?it(p07+ z-b~Kg4l}EzP3cw3JE!Noce!;}Zr;UV)Xsoo$9Xe(-aTSc@8E?aWcRua4TEH)8Xx^1 z<8YwbY1)pvBtE-43r4agDfDE=J_J&sQ=3(%my>!qfmEtj(?R)|C>nBo?J5&IdF) z${T%9r0-h$*^_ROf)a58Wonz~GTSx9NY;jf^*Yv5=jvE1XCCd!3bnpJNv;Z$SUSQX zJX**HoUG;-s{bg_j<>I;y393u5w&Kcb8=%)zG61lem{*IXP3Yj#+Y_Gpc=)0eaJOv zwobO>F};Dhp{JeW>iAT&#>?7iac@MeySNyzM10ez2SQMJTDz0UwxNGQ3_t6uP;NN| znSSMVlW5?7Z@EFq)SnhVyY6bXO*A{e=#O-6>`NQCOG^+7Ml`LX{2K&CRW6Jp*Znpr^ZvFNK&@slZ#Nw*tFcDWLsfHc=UHb&Zgv{>|%TqaeAoh5F|U1_j_L$BSGH+41@``exInvZeHI;=PV@ zT#2OIwC6`&#M=F9{B5CMq}blsQ!;_BzM*%Ke7PSQ#_9EUND^%mr2|b<=Cr6zwHgXtnCGI6&LIf=0W8mh0j0Vp;8)v+O{sV`k0$#f4M;jCKK%4a zrWx^EWu2N&=7)s8Ha_HafQ9FNF3%ODYOs$wllr|t;9q(0c;hj>2Jjx8V+-=>c&rQK z|GU|n0-yo6-7I>eRrqYY#{(FpLY)Bt10IRQ2v!4DHjfn1d$B{&D@F8jp%`_tGnR#m zh=9)DitZ-6)4(;D$M-mT@3z%A3I1MEj$hn}fPFE4E1|TRFswF+jH_u$k!YMlE_kKC z`KpTIa>{a;7z=UCd646A%39`o<$L~TQA`^>MFgnrkhO-5cw@%+Sh349qPL+6H~`Qv zPGDEcjlhvle|m&rx#Q{$AehYl8l>x7(LFspk1LoE16__E`VS?vs}Ye7+`L1Nm>da( zN>XHa{rfOYmpHINGN+iXv52cogjNGp5Oj7tCr^3-DtipnHTT&yvbRc$pydPF8NdFQ z9eHXF`+8=<52d3ZfokW6)7=cvI`RW)sIii3)y8)Lhou+N-s)GQ+8aHjs+KML;Fd*T zBIiMx{kz}%P*hn+1Ru&(UYR*m+_gJX`YUU+WNgZ)R1u0I$R1w&iMZ|J;!^4(LED#DUd z4>`ju8)=y|(ji2lFeAR&Bgwv_%u$j@Qs+pp&8>pPI2a_*z5zA`_*%BF4kR#bmRr$1 z<6f(w(ue+2uB^CyjAeRz@QUPL!6xIE~5 z>HqjTy}NdC@aj4mNC#s1!Gr$-=5=4(cy4&o!7V`F;PT39Q&9$lOf+5&f`wa~xPh8} zoZ$Np0GiYL7Hq{t%~I-(Lp-0L7D*j8SDP<0;Y6QZ>_!{M9Qt#bif7zwI2$kjF;C+f zzb$DKijY19%{O4no0?{abfG2Y?WMFalu1A82DTP1_TQ&K#(R8ny}*Z4{P1PwZ78)A zuqyCMq{$YE1I4Thw}!%L2B7O>z#EBeG<_L0#@;&Lx&bPYR%6CmX8R9Q*rDaHy3d32 z-Ta9)&P_?Th9dh)vCiG-N$nz^W8zP!f_T2a)2WcfBacn3jSX8|%~$SR==f`v_OULC zn>55jY5|{v2jS}&T>Eq{%FXSV1)lad6Qq}kPP#k`T%H}qk#TPokkK5+9CF2i$KySQ zE!EJ!l?JIdAR5QKQg6}#YC3i^WH8MPo&coqp(s@^&&q?j#*F?2pVs>w=3NJxA<_i(1-HoUlFOPnI1{cK4=do?Cd?x_J zXzUfvSP~Wp-zo**0>i@RhZlBFeYau{@i8I1(hY%a?_WgMu+MszcICN$<#_hprQg6e zag*qjUuEd?D<(2zlL2=IdO*~vLCiN12-WF zor7aMXUzd_+3n}jDWkbfO!A#)=sUH<{K4jCGbiE1Hf0+cfo|;$w@DuA5r)bvc(MQ3 zW_`rO=#0G7GLpll?~~^au{rXzRK}N?&YuI5tsMTXYC}giN#O{9-ud;YVMmg_R2zgY z&Uv*@$@|6hS|O%)FXql%3(Wi$VRmnn5&yq%d> z9jCm1bI0sRzU9Tea?tD1$u-n|vo0G-P40-jki;mZaGx(`OTX znty!s-w_dM5FxNv7auFFZmFq;{5zhGk3F=JfxA|Y5dY#75{)h?N?Hf_LG`&#AwSk+m~t|Fq+&-0aBQ{f*$bpD7G+ROjyPVoS$BUymXz$xl#t!ltORm40Z_ ztMp5Ut?SM|{;`LR7`M@VR<-NbHvRX7=#cQiwTcFeV6obDKSTNsQf%~?LoA9f<@A5v z5uP9^&7+A`N&0&2D`{MxvLvEEw{P9l;>9NC34q6b_yr$;Hd9c$p`V!#(#-}+R-Ba~ z%-Zk1tagwKFFZDn6rIc1)h!%9QGlH^f75vQH+VG2A$)&|*_gOP_a%ky&l$qL>?-9r z;p3bMe)}iz=>rYdYu!mpqqOGRhotQ#>RY1^E~GpIGjJ`RV;er$vv(WZKdIZ1oc6yP zbS<%tdsf{>PMfRpfz!qvuB%Uuq`CHQrrx)(l34Kiutev^1}8+SC=y3&pNObH_|r#> zQ|D;(+tpsi#E{+Tm(&sbP!R2sOu>F%(62pNlikACZ8P&KuXc4RpH<5UVCS7RVc_7y z!{Ohzbi$B|>i1wsXBfPt7N9()P<&&Ct2PB9q}Cn56RR?_2+ zT;rPH%~2XnNTQHyzS(HT=LcR?Nt^+0D>+k)Tx552oE;wMIe{mOBxBwOxoLqY45e?1-BWqs~5a#Ub06^d|YRc4<~6C41COwvrk71s+aDi zF^KhL!NfVc{1bkF@Wm|C=;~u?DUOAOJ=CWzOHB@fSIGK$;<5gtBWD9`^0I2r5W4XI z^$3b|Qa+7`6j-AYc6uoC)51LQFad*bDKL#`=f(c-gTI>{(pMFcfY5N)#Kpbm3x`c_ zj|ozL;fUtH`)*0OT`E9%e+ev_&i<{Wsm1dH8)JUcNUxy%GJO{yJ+}q~UZ%OiCsY1@bvsbqAqe~OOsHD3!Okq~l_B-<;=sq49|e)SWhC>F{(B&n-K1@lMz%#48F z!?)u9IRe1H$qSk-dq%D*por7z<5QUI1RMTNl~q?vM0;-Iz3Csk^p#2xARrxUv)G%* z&F`mSS*id&fxvf{^}+%&!n)y?-RD5Ja=XDI#z4K)Mi9WKr>#{oJvpZOd_}~V;Y*w= zj92EY;C{n&Q0LN_+~Z6K-WY%5iTQK{q3dqg&M9kx4Rn;_EloC-IO~PZSrr^3_d0RL zxm_wt{}}+a?6Fmp#ox!K$5}V{IF{9oVN03SXRgFK<2t@hrjt~_{?79OLNvXupRxE1 zzq?8!0i$7-#Bh>QB))O`MSgfyGp3;rDMhW#0hT}~9^OPEGL()`c@7cm1mNoqhKkVi zqXdURS00sR`bnm<#&Ntgk5SAVBwjK2@Wq3@Iy+hW3XTqm`NO}P-~2>EU;YOrmtu8c zRaj!yv+B_);FvQh{au+FYm~V0h~=q02ur9`!T6(avN{DlTJH2tOv`Z{P9z`Tk7Fv6 z(qp7GIAS#9<&aN;lx_;%NyHp_7zUZGW!n!%2tOaWS|gunN=Y5zQ#T&-j@jJOt3Y&S;XCw%XP$7>XR#mTV^7fEltLsU_c5=;13w4O? zpbB?GoF2s!FmCrZku#S8gtYlPi=d_c3`VAG{NBzxj<&_&=sF?(bhsF)GvScpchzGh zlq9~N{>jDqHI6rbEL&j!ffPfEaSL+OJsIlHi*QD2SRNNR&kI2NVMoMe;XE9V6UL9E z60@&x-SNzXBVkl(0epAd@$2v;NWEY$Iy30Zeci9xe-HuTendE-IjTB+PlI|aRHKrc z!{WHQKQ?3RJ(^#t$x8C^f18#~TmBc4nWV{ndwcZRaF1mMnq~aI=pIqKU)S@MWh;UFh=unYA})|O99PUs8+(p(JK8Onjb z{qJZ+UfV(Fs(r*isB)8K)AVEDb%5>ge8@FlM6PVv&aktMyKPOA7d>o%jy?wsv zlC*arb(BgV8GjjvA9fJZc!OXmDb)|`F8q%Tao7<7wB;R3X%mj99Cyn!2(MUJXdEXu zmUYO}t7Idp9OvKD%s=GSRNIE*HNEAi6bhp&2Pl13z3qn~>>!^qDAl~MfBeJUl<%v5 z?^W)ctj!ehNcRc$peaXXZX=AFdB_TCK}D-77c4oVmTC^n=l@+qhy>`#M+`6I;MT3) z%sa22IBJU;MuLliK=#HB7l*w_K6L+2jx=bxF|p%YYlG%y_C_^K?5-eOdWP^`%hGRK zWnIL}x@uQ#7@fbQt+LF>x^GzT! zuD|)yXT~+cO_Wih@GM$tYCx4>>97(7!l2VgfV1$)dIL^hKxfreB|$rKRL8;!IAoy| zxUB#e{wPFB!``h@R2+=mTk_*3{0l3{Ae8)Bw1}NXn}Kb=bq@rKrnz>9!a(xKAfJ?8 z$wmixJNQ^n@=qrI$b3G~d>#-iO_!i)8vQ5KXYt$574L769T4VEm#_s9kjEVOUfj~H zZw4U=Z-Xl=V!8q2=o$#Rvu}V`u~>gmiNx}6)qmiEtWbzn7hnJx3no|J6TOeV17qC) zWd{g&s!6XsxXOBJ)9Xj^Zq%0s0LvMAevkN}){8=SfmAXOR7PopPxiYGq` z^hGFd3yE^gsaKtn(%co`R5&=1oBH2^X^De0e2E2Amzkg|XrWkhIE*R#nxH>B!9f_| zsO7Hzk~Qcb2;O`4;1yuDz#rI@j_xELeRxs-y-(x!U=^#WzD}~Mf!$GR^N28*v`pVI zIDj-n{W!?ON!#5=7GpC@t8sHK|YI#5y7iUvr$u-V2*_#-gB*&1dP|T$w6yc&ZeSixAk+T zb$wy%Ijw_=|H`Ve$o{G_1_noGF!qWUk-j@V6woLutpVzWdj9^Fjc%(st$VU&^5lrSX z<=sY)1d*gCY(r}91O!STCmui$otw2245tE<1-DPf8uDJlHSDZpnU=oPN;{7L0C28G#^CK4WOkrhNSCW5WcDcxwq-Y$rD*F|>q19Qk# zLk*rY6VCg}r-zS>n-#%{Am;Rw62!OPP!QcLxNT-g2ysPE3{w1|NMuaO*L1Lp5G2Hkrdb zNl}ZQi*6%oBUQ!mP9iLE)SyW2;lt8_nPA8fHPti2J&)PtkyU-0_Yzph;haP`L)R@3 zfLW?QlQs@Q&95@O;J$O4nGS>vfdtY2Y9pPu)Pp9%`-)*)=?tvx=E}zD9N;z9A?MZ- zJK+5TTmztE|Bp$QvvWWDX)5G8&l&btfxq$4>Ql@!3}V*L(LNzyIaPqO-{V9vml373 z6J@Wg4TDqMD(p`F?ywC4jU2IbN5lOfDSVr;+W+)>hgMMOyplS+k32$Xay(ndJ{E;8 zkmidL|7s74T?_oSSxW{C;+e0(VOPb!YB`74DKCKgCrV3834D{JH;*j#%EPK2Fg5<| zm}R`PW4^wiq^_K%+`_=D^4Hz7>Po-|P=ezN9hagF@#XKy5c3vAAg8o_@OOB*c-Owf z$~SK%uYkmv@M8&mSj*C?$(<}?LMp*fgAluRCOc)5y4ueBK5dI$FC2Q*Utm>j88s?D zdutx6kn3hX7Zg!5#yenyn&bypD+$)cx!1x%0#SUvT-XMe#;6Lei|gQxik4uXSSfcp zHw3-6{`*DS$q;1n*I-tV&&SX=8&Eo{?9IB?3B>J!S_GdAU^Im`bHjgD=I0>!G)#+DKR48T#Ey)_*AceL6VM+Ix;r&f>Z5 zyWc$vgw{4O#P-<5eGJ)2Iw5yUQlFD=XCm)8<`2=5bpy)_Au$Z9XSmI(?u-4j?de&a z!m0hW3d8+dZ(40+_Aa@FIDSp{1%u?L^pwY{PY~Rin3#}HV^JW)-gtu81tbrY61NkO zjqypn!)vW5*o-N)UNNd)0x~Fj4S9k_8Uv=HVIvaETl zgPgm~>esrKwRe%+D{r<0O8?~uADX@0e-9Rf%;^0guu3!G^jv0#4G!T7F|Z6RY#e@i zlf}-G#>K8$H?%>xa6jmVnGpBtGhiAnpCn!?_qHS3c~^nAt3O#GqP9yPCHcnFNISM+ z@3^(}=H?Pg8z$FQu1gku*#+|SjjTM|?-msIa(K5NDZ^L6mj{j^1h4KnBITJ%o_$CA zdLQ``J1yJ+U0N7_|H>V|o+Tv`qF^Ctf)TH~OcRKfCe4$mnZ%p^l_fQE(nE(i;1Wn| z(f^e!ACY%OFv!~)lIYwBBZ?)N9tezSI#?$x0% zd*uv+%CHy9%&Ys;4%}*z`;Y&aB2_#4tYdOp9?jz-@I$zLv2@ZXnpnu~?qhCyCs9LFu;k0C#;6tPuTthHUilE+s zH!24vT#MF&CGgei@XUm?-ozhcL6cpH&A?8(nvP?0U*v7w(}n$D0XiaH ztPnStq(}Kr@6Oppk0wTz2%fHR88fK~1hUzYo3;(3F=w_|Iuts#FOCC(WPWtFyNUlS zu4_XOPOz#kQ?g%uP;*_b(cmvz`$mVaJkQgh7oTm~MDxF{@-{?Nex~!MKQsF8LmMMH zVb10I=OBY44(1g^cE5RPwREH2DoVumok%(5i0!CdOJ*`=eEypmkBikuD{!U*f-{Iz zl&_xPPpPGqBrB&Yn!eVzj#h%&WA%UqXEl~*;4eW70qY)A!~S_dCy{<~`2CD|W+B1C zv@ey~;oM~ZH7au6<>13a*a?gTw{b9_Hj0KXxMl-kB(7_z(*SI56GCX zOYgdnlJ6%?d*kdd8`#lINjmp%PC5h4cvGU}pCDKUKnuQx_gyD6S(S!LXI zZVbiCCT~+9s2S`SAjhq{K;(-;*yUxgVh-Tk#kZxXLa1G-CDGABFSf&a|EJ285u921`zfzhnoKyBhEbgNwVv6k5guoWq;TY+42MOdb95uL$N|X0DwfaC&rql zL8mJ-ACdAgS1!g6{hm8aXgQ(KebXq8rG9eE!y7j&x#k^_4WU*ax(i}VK(mEx%p`aQ zG~0G%njj)!$B(6Wda^4q&KOpghsCmMDB#?tQXtyARJsx^G2uLI+P4h8D|(^b literal 0 HcmV?d00001 diff --git a/website/images/align.png b/website/images/align.png new file mode 100644 index 0000000000000000000000000000000000000000..1bdf51bd8c4dddf27d9bac18b938b287aae6856d GIT binary patch literal 3403 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 literal 0 HcmV?d00001 diff --git a/website/images/banner_bg1.gif b/website/images/banner_bg1.gif new file mode 100644 index 0000000000000000000000000000000000000000..982c50b8b508d44252dbe4c77537850611160222 GIT binary patch literal 800 zcmZ?wbhEHb9Q5emai0W%WCYOv3$iUpPXjDyyos{bE>+hdS^Gu`sMe|m}e4ODeapl=bt}+ z@v`O#GaXZFJ+d2T&0nk>Sd?7b6II@sSltCQI;^N&$SpgzqO+!VI-5gkMt!eJaN(5M z3tiJ2rq5qAZ_(1$NwWhBTJ@qzozv?zLQDE*%r}j%sO_6Eb8~7O)d^KqM$m7})$dGILA!SE;@-D^ zpVXnlhs2K^KPG+Z^eO*y=g%o#x_n9J+VyLmw{G7uy?6hf=_iqlre*X&i_y3;&hm6LDj)To?wi+=jCbS)H=Zp22qw%r%Xt$Vd#+?;` zO~?D?)H`G}gW66`R-3sZX62=p)6?}zPt4IQZaF*KEbzshm75#R&$sjBkktxlxwzPE zqDJhhlGe-1{g!*o)e7ynx;kuX#@$t0+pn*WEANoizSe$obDHFe*wx#bZg0=44L&hf zTfF`5?lQ#}cUNz3zQ4aNnL|$JM#ICyZS@*)Yi2Y(KHg{OF;C}a+tbt2rf1w+GqdaY z`FYVDa=KRSFE1~PUlF%fs^#_db>1iD>CSF{dwW~ri+gKlH^0BXkDo(cucqVU<70C* g;@9nI{QUf!tjByk+orFtuQ6uaKeyMq!GXaV0D<{N_y7O^ literal 0 HcmV?d00001 diff --git a/website/images/brickhead2.jpg b/website/images/brickhead2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..333a18528c4832cd8ab50ef41aecc639a229d965 GIT binary patch literal 10942 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 literal 0 HcmV?d00001 diff --git a/website/images/brickhead2_line.jpg b/website/images/brickhead2_line.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e35d216bcc334414359c0f7eff172411fb0b3b45 GIT binary patch literal 10969 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 literal 0 HcmV?d00001 diff --git a/website/images/jabaws.png b/website/images/jabaws.png new file mode 100644 index 0000000000000000000000000000000000000000..c9b340f0eca6e4fc6bc0a60efed20bda1530675e GIT binary patch literal 9622 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 literal 0 HcmV?d00001 diff --git a/website/images/matrix_bg6.jpg b/website/images/matrix_bg6.jpg new file mode 100644 index 0000000000000000000000000000000000000000..95da0e1a53239fc24d33d6fbf5e18ee4642095ba GIT binary patch literal 6315 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 oFriE)Dz(1FVtN|Nr&% z^%xi!85tQG8X6lL8yp-Q9UUDW9v&YbA0QwgAt50mA|fLrBP1jwB_$;$CMG8*CnzW= zDJdx`Dk>{0D=aK5EiElBE-o)GFEB7LF)=YRGBPtWGc+_bH8nLhHa0gmH#j&rIXO8x zIyyT$J3Kr*Jv}`>K0ZG`KR`f0K|w)6LPA4BLqtSGMMXtMMn*?RM@UFWNl8gcN=i#h zOH52mO-)TsPEJoxPf$=$QBhG+Qc_b>Q&dz`RaI41R#sP6S6EnBSy@?HT3TCMTU=aR zU0q#XUS3~cUtnNhVPRonVq#-sV`OAxWo2b%W@cw+XJ}|>X=!O{YHDk1Yiw+6ZEbCC zZf7mzbECnVFfInwp!No1C1Sot>SYo}QndpP-Ll?si~=|s;aB2tE{Z7t*x!DuCA}IuduMNv9YnTva++Y zv$V9dwY9ajwzjvox45{txw*Nzy1Ki&yS%)-y}iA@zP`V|zreu2!NI}8!otJD!^FhI z#l^+O#>U6T$H>UY$;rve%F4^j%goHo&CSiu&d$%z&(P4&(b3V;($dq@)6~?|)z#J3 z*4Ee8*Vx$D+1c6J+S=RO+uYpT-QC^Z-rnEe-{9cj;o;%p;^O1ulq(=H}<; z=jiC@>FMd}>gwz3>+J08?d|RE?(XmJ@9^;O@$vEU^78ZZ^Yrxe_4W1k_V)Mp_xSku z`T61p*r{y9LEMIBcnsB$neT5U5wUkA#V`!ra2YfY`UDsNzrho?+dtsb00000NkvXX Hu0mjfc>&r1 literal 0 HcmV?d00001 diff --git a/website/images/mm_spacer.gif b/website/images/mm_spacer.gif new file mode 100644 index 0000000000000000000000000000000000000000..35d42e808f0a8017b8d52a06be2f8fec0b466a66 GIT binary patch literal 43 scmZ?wbhEHbWMp7uXkcLY|NlP&1B2pE7Dgb&paUX6G7L;iE{qJ;0LZEa`2YX_ literal 0 HcmV?d00001 diff --git a/website/images/panel_bg.gif b/website/images/panel_bg.gif new file mode 100644 index 0000000000000000000000000000000000000000..1b3030d8fa55366eda8a8fa326614bc397a558b0 GIT binary patch literal 1901 zcmeH``&W~79LJxHZ48+L17QOk(*^>;!c5`T!;>hAK_uEtG*4|X6*!tm zs0fw=6(p?#DvDhPBZbpN5YTaz>+ZK_d%oZ2*-4}MPxMotA3xXk>wV5=Q)=>>wYe9N z1qhBHC?MwN=bz}X0Uh?t0H&>Q)C7i&z=jcndTh!HO%B`%2?L7jQCwpL&n<93k73X? zVgj=^IHbph444BDT03rZ;4?OeLBj0BElzyQ4D7F#fFV5?H$yuhbSQ3h5|dUqZU)Z` z*n}BAHDH4}Y{UqrEO5?-8yxOILSq0{44<>Pt6>b4HJRRKG|Ef_wib0Yv0BgQRIi$a?d*SNtgaNG^zAnX`E zVuS`1YHe`ZiqG2NhzX*QK>m;a%7K_yhhF^xLZ3&dbj_PdN?D8_Q%p6MyK56 zHkJClwn}m%NnV;%x4~z3`SIdOgvs-dP+b!DsC?hzT!>jaCFo{_z0F0=c{Jpo363p| zjudlG^@j#WifeP#)Ib5NF*&tbp$PO`6r5Mo$1SU-dcU|lg`7~I35iQkRiQJRyeP#} zUlNFtFZ0gn$mtMk>17eJ<`mV6aM_faOk?y2i<2l(9+@J9G~Gb0SQ?!**_OR$6FIW0 zo9>$QzEmBR-OAdnZ1?owNcF9UrWNJU+cOZu@PNXL8XLffRVnt%mjzdfTRR7-CpjA$ ztGNQ+&9WfPkNc1xk+h2;pE&_c)>a{I7DqPs=F7fAi=bUO1Z)d7Om? z$}6J+JCTAxR7^gcA`#F7^B$J5R`uE0q}=sMNUG<0nJ6`)t#9O1!XJ|QqPJYi(T@|` za~~b(VsDaUq{XgQpJw?AM4W*S4=&EseF1uy>A)b2^IiSY3&keb_8U?ANh5$TUz5t3%{bEB<2+fdYP6NKyA=G9d+Z7k%E z?PDA`lvRB>C`8=sc|`jl|H{*Uc>BE-%)OBr75owX)vc*%QJEJHoi~u{t$l{(I7LE1 zOLNzC<4-{yJ7~9VKRGr>yPwW)7Zk`Ilm=9lt{DRe##m&A~mK;kX+z@ zx5?wZl1gz1XAQdbL}=m=Lh9{er<3|*G|^Tiou8sy7*}0kRu z8`dG-8R@&*d>)A66UxuL%&78D6ezzaqNgLCTWj74KSfp)FOW7eTX?>5iljqAl?Pl4 pF(>T|B?6YDsUG?~oZC=w=l7j_ZWyiaTQ6p9>Fkb@S{Z_@`xmVTJ8=L2 literal 0 HcmV?d00001 diff --git a/website/images/panel_bg.jpg b/website/images/panel_bg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..521b3d484b9f6b49328b0098959368408a38af15 GIT binary patch literal 397 zcmex=}+i8T-=63e4^sQ0>a{O31S)l4=@OFFmN$UV`da&U=n0x7G(T?gdv21 zk&zMTNCaSHUShvT76gXIy}8ThHe?z< j&<3rEoQs-09abzVnd7&(^HQNzpStIP6-~>I{=W$Tz=H%{YNN@`rNawZq7D)QLmMi1B{x7_g$bBf zI7SGFH(Z{|OJT#1P@QP@NAy#lA3i^P?yvVbpY+VMFHhr-eY*y$q_Rgw?h}48ZzN7FlBKP1_$gj0GuFE zjCg4U8Z)%Hh)Im-H2~BBdr>!zyNonBi04KyVu5Otn-OTNZdq_AoEo*dZy+aZgxUo9 zP+-ML2bj{@zzYkQuoExb(gF8X00V>-C;AO;1mM6)jTP!0(C#9J+~8KIaf3KX3@3(7 z(CC1AI~=zWIt&h*p#zf0|Mp)guwaVz@2c2W{?$()jA_J^F|?H1B#C8n_?s!=%1>!w z;W_Ohp1^ZqT2cFutde_im2bZ6h`4D{y|+l+=^K zag{Mq+{6>vKK@a^$j6$a19(C4{LK35>Hx3JbCZj@!>Z~%XZ%H`bW)fn=Eg5q)H*I( zPjMLI;Xw|HWb5~Vcg6RFdPY^Gq(M+8c|S|iDf3&rEmowE#L~R@wM#{-t7X1%MIEfl zaNij#lgs(+$TXGLcGVXv70|^Uy~8h>c1~JpUV#&EH0g$Gra2xpZ>B!?Rl`MtefY( zdja;=;k`YZ&TTD0YSo@c6XZ%drzBdLx1AoP&!aEPX_ERxAlZzP<49_CKyJ&UV?pKq z^?o58PpDb)xaV% z>42hEWEGia2}ha+gF{r}$JZlN(_ys3rN5K~o;i{rRA^+KZ0^P4w$|_7`|wszQbWm|R@Ii~Ro>~1HLB>J8uun=rH9Z5^X_b_)l}T! z9+)_zjyWXg@S60(o_-Km0mrV)Kl-=Nnj5_O)huZ+b6uOh(_83&g}rj)-8v?1$2^Y{ zUPpSyXkpaKUYh*EfpJa+TIeS(gB$3`JrRX%cX z^6`EU>g^G7^C5FF)lz{e8T&V`8r}AA=RN6Q?zl*Pz98~}xN|-CMq5|lrW-wJbNu89 znW5)sOF7}LV#(9xvC`YmlEHMp^XG)QukWQS8*SXXVMY3Y>vx{-4_n{Kn&*?#J1GtNAh)Ea$du!7mremUS^%(ZKe6xXiHpJiRYxqqu7t>b(6hncQC^!D=i z=~qkj%=Me~EXJ<&U6H=HpZM$aUXGS_DdaYno^?2;XUzx_#n#b%Umx@MNQa%)`k%<< z^Ez9igfv04uSXI}IaQA&&Mz)l%&%{}s@OvhYAMJpDPD6!=ajx#qs>9$yE-1Js~678 zd-IPunkmkPwpdpCQszM!e@A3JlE76lVwxzFFYfaHdb+#(+ZEnf8Hv>~7gb4g0c9=g z4E4*qsI+n}ZER85l2p;o4d!MhJA;*&U7(o3kLjiEmRB8${$v)JdTOSQ^W{|~Mh#S~ UyM-*2M(_Le$O^uIiy$lh0imQ*9smFU literal 0 HcmV?d00001 diff --git a/website/images/plus.png b/website/images/plus.png new file mode 100644 index 0000000000000000000000000000000000000000..865e538ec75a11d52d0cf42c5df87ed35d9fc32e GIT binary patch literal 211 zcmeAS@N?(olHy`uVBq!ia0vp^d_c^@!3-o*<7!?2DajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_d9MOpzqA+G=b|L5#_$&io#l}rjRle`nTh+Ss+ut7F zubvxqcd&jJyc1lY+;o4&%$L^BRClyL*w?gMe}&mf{{}_|`-RMr6DKJ)1C3(vboFyt I=akR{037sB?*IS* literal 0 HcmV?d00001 diff --git a/website/images/uod.gif b/website/images/uod.gif new file mode 100644 index 0000000000000000000000000000000000000000..4d5877390a4754f87597e27f910dcf71e27f2055 GIT binary patch literal 1542 zcmV+h2Ko6%Nk%w1VMYKt0M!5h?V=sn+1K!H7qYXn6ex-L6%eMRrHP4&Qc_a%(9oBc zm+|rO?db&gJFh@`r_ad3iB0F=l3FTxX)g!^7ffWXs6I%*@Tv)#ddw687~N z0s;d0`T2*Ez0}gp=<4%=qfN`w&i(!UdV;MqMwG|L$MM)3(9OlDtG({`BK`RH$Hl-0 z9EAV>|Nj2||Ns8~{{Q*t=bfOpx6C@cy}kO|+wSo9_V)I}&@(GVbm-{l{{R2q-{JrM z{`>pb*FB1w_4-+pH2N4xGbd5tW7z#fF7(0Rk zBQ+BU4=)S`oF)-2hY@R6syw2!jVB3c6S@VS<4V2N*Dz(1XXa2bhKo@Mxf- zqZc?PnTmj5REK;Tg*=eZBa?yuWp2nB*n?w7&LW6}h|1XLM~6ELeng;ll*o$(Azux^ zp@3i)1_E95P|%^rkE%u<7&uU)Lxc(FyttXbNP$tb_l*2_g+L8eFQEJ|t!mOppo4Zh z6y{>m!~mB@WF(kOxw7TUD_q1lvY^8Phj<|r7)_eA1_7m0Yp^jG?~)OsQ1iLICg$!36}D9zA!Lvq?-y;2_~H z6VVOQ3lJb2`UU~E8?0||LilmyOMD?PZ)7|N4ihi|gAbx&xS)k)|C4E`a|8W9Kl$3X>6z&4r&IfRfy zeGLHMV~-nz5Q1of55zdZ0}nqyV8NJV zmTBghs&Ik8e*qS;gMSftwFD0ylu$zeBIJpI2(s|0rz{@?P-g~R#7Lf;E+F}z1dt)| z<;9p!tjPN284oFI@q$IFl>7^gk zP^+`Vg5ZUJ3KTK_k_2fmhJm)*8fym%A9&C#xg~(-#1Ct7(C!e1a)1G%N`OGFvyysH zgQo`aFK(*Wen(g*_=7>;S*cONyuf1@~pLjWx3t#=P{=QIN20xxsb2PiD3o120!1H%h{ zuP*!SwAXI`yK66GBxgoi!NlHC9w8V&0;B7T35;T)1qA9S1{4AU(j@`MInV|3 zdy^f0@}|2W4TbDNKmcN3q3#uzz}6< zgeDb=KpJ>ZlLhpEBz$NWl76z24=jLxM!Dbu7@z=1NT41D0988BfQA|j!4e&*01O7G sfPs`F!HpRB-Wis5Jw2u?A!s;2Ix#`s7JWo2dV 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 EA6ahTt^fc4 literal 0 HcmV?d00001 diff --git a/website/images/vmb_virtual.png b/website/images/vmb_virtual.png new file mode 100644 index 0000000000000000000000000000000000000000..f64725fa3efb53332c77366b4b1be605ecf6490a GIT binary patch literal 21851 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 literal 0 HcmV?d00001 diff --git a/website/images/ws-structure.png b/website/images/ws-structure.png new file mode 100644 index 0000000000000000000000000000000000000000..791ad9a1084eb647869fbce93a7092fcf6730276 GIT binary patch literal 19953 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 + + + + +Java Bioinformatics Analyses Web Services (JABAWS) main +page + + + + +
+ + + +
+ + + +
+

JABAWS

+

JABAWS:MSA provides five web services for multiple sequence alignment: Clustal W, MAFFT, MUSCLE, TCOFFEE and PROBCONS conveniently packaged to run on your local computer, server or cluster. +JABA Web Services can be accessed from the Jalview multiple sequence alignment editor and analysis workbench to allow multiple alignment calculations limited only by your own local computing resources.

+ +
+ + + + + + + + + +
+
+

For Users

+
+ The Server: JABAWS Virtual Appliance: (520M) +
+ The Client: Jalview (18M) +

To use JABA Web Services on most operating systems, just download and install the JABAWS Virtual Appliance (VA) and point Jalview at it.

+
+
+
+

For System Administrators

+
+

The Server: JABAWS Web Application aRchive (45M)

+

JABAWS requires a Servlet 2.4 compatible servlet container like Apache-Tomcat to run. Please check the quick start guide for installation instructions.

+
+
+

For Bioinformaticians/Developers

+
+The Server: JABAWS Web Application aRchive (45M) +
+ The Client: + Command Line Client binary | source + + + +

You can either use the JABAWS Virtual Appliance or the JABAWS Web Application aRchive (WAR) from your own computer or a lab server. The WAR version gives greater flexibility but requires a bit more configuration. Alternatively you can just script against our public server (see below) with the command line client or you own script. +Check out the quick start guide for further details.

+ +
+
+
+ +

Public JABAWS Server

+

You can access our public JABA Web Services with our command line client, Jalview, or with your own program. Jalview is configured to use this public JABAWS server by default.

+
    +
  • The JABAWS public web services address is http://www.compbio.dundee.ac.uk/jabaws
  • +
  • A detailed web services description is available from here: WSDL List
  • +
+

The maximum number of sequences you can align with this public web service is 1000 with up to 1000 letters average length. Should you find this to be insufficient for your needs, or if you are concerned about privacy or on an unreliable network connection, then you can download and run the JABAWS Server on your own hardware.

+ + +

Publication

+

Peter V. Troshin, James B. Procter and Geoffrey J. Barton "JABAWS:MSA Distributed Web Services for Bioinformatics: Multiple Sequence Alignment" +- paper submitted.

+
+ + + +
+ + +
+ + + + + + + diff --git a/website/man_about.html b/website/man_about.html new file mode 100644 index 0000000..ac1c686 --- /dev/null +++ b/website/man_about.html @@ -0,0 +1,122 @@ + + + + + +Java Bioinformatics Analyses Web Services (JABAWS) manual - About + + + + + + +
+ +
+ + +
+ +

JABAWS MANUAL

+

About

+ + + + +

What is JABAWS?

+

JABAWS stands for JAva Bioinformatics Analysis Web Services. As the name suggests, JABAWS is a collection of web services for bioinformatics, and currently provides services that make it easy to access well-known multiple sequence alignment programs (see the list of currently supported programs) from Jalview. + However, the scope of JABAWS is not limited to multiple sequence alignment programs. Future versions of JABAWS will incorporate protein disorder prediction, BLAST, PSIBLAST and HMMER database searches and many other tools.

+

Getting JABAWS

+

JABAWS consists of a server and client, but unlike most bioinformatics web service systems, you can download and run both parts on your own computer! If you want a server just for yourself, then download and install the JABAWS Virtual Appliance. It requires no configuration and is simple to install. If you want to install JABAWS for your lab or institution then download the JABAWS Web Application aRchive. It is slightly more complicated to configure but is very straightforward too. Finally, if you want to script against any version of JABAWS or are interested in writing your own client, the JABAWS command line client is what you need.

+

JABAWS Benefits

+
    +
  • Can be deployed on most operating systems, as a VMWare or OpenBox compatible Virtual Appliance or a Tomcat Java Web Application.
  • +
  • Comes complete with sources and binaries for all the bioinformatics programs that it runs.
  • +
  • Can operate as a stand alone server or one that submits jobs to a cluster via DRMAA.
  • +
  • Easy to access from Jalview using its graphical client, or using the JABAWS command line client.
  • +
  • Clients can submit jobs to any JABAWS servers that you might want to access, such as the one running on your local computer, your lab's server, or the publicly available services at the University of Dundee.
  • +
  • Local or intranet installation eliminates any security concerns you might have about sending sensitive data over the internet.
  • +
  • Wide range of configuration options to control size of jobs accepted by a server and the command line options available for the program run by a service.
  • +
+

JABA Web Services Programs

+

JABAWS currently provides access to the following programs:

+
+ +

What is JABAWS client?

+

A JABAWS client is a program that lets you run the bioinformatics methods for which a JABAWS server provides web services. +The most basic JABAWS client is a command line Java application which can call any of the JABAWS web services methods +on any instance of JABAWS Server that it can reach over the web. It is useful if you +want to test, or execute the programs provided by a JABAWS server in your own scripts, and do not want to handle any web service +specific details. The client is open source, so you can also use its source code to find +out how to work with JABA Web Services if you would like to write your own client +software. Jalview, which is a multiple sequence alignment and analysis application, provides a graphical JABAWS client. This client has the same +functionality as the command line client, but instead allows JABAWS services to be accessed in a more user-friendly manner, through a graphical user interface.

+

Programmatic access to JABAWS

+

JABA Web Services are WS-I basic profile compliant, which means they can be accessed using +any programming language or system that can utilize standard SOAP web services. +The WSDL for each service is published on the JABAWS home page, and you can use this to automatically generate +service bindings for your program. If you use Java, however, then you may wish to use our +client package to access JABAWS. +This package is based on the autogenerated source code produced by wsimport, which is the Java tool for creating web service bindings; +but in addition, offers some additional methods which simplify working with JABAWS. For more information please refer to the +data model javadoc. +

+
+ + + + +
+
+ + + + + + + + diff --git a/website/man_client.html b/website/man_client.html new file mode 100644 index 0000000..ce35521 --- /dev/null +++ b/website/man_client.html @@ -0,0 +1,111 @@ + + + + + +Java Bioinformatics Analyses Web Services (JABAWS) Command Line Client manual + + + + + +
+ + +
+ + + +
+

JABAWS MANUAL

+ +

JABAWS Command Line Client Usage

+

The command line client comes as a part of client package which you are welcome to download. The command line client can be used to align sequences using any of JABAWS supported web services. The client is OS independent and supports most of the functions which can be accessed programmatically via JABAWS API. Using this client you could align sequences using presets or custom parameters, please see examples of this below. Here is the list of options supported by the command line client.

+Usage: java -jar <path_to_jar_file> -h=host_and_context -s=serviceName ACTION [OPTIONS]
+-h=<host_and_context> - a full URL to the JABAWS web server including context path e.g. http://10.31.10.159:8080/ws
+-s=<ServiceName> - one of [MafftWS, MuscleWS, ClustalWS, TcoffeeWS, ProbconsWS] +

+
+ACTIONS:
+-i=<inputFile> - full path to fasta formatted sequence file, from which to align sequences
+-parameters - lists parameters supported by web service
+-presets - lists presets supported by web service
+-limits - lists web services limits
+Please note that if input file is specified other actions are ignored +

+
+ OPTIONS: (only for use with -i action):
+-r=<presetName> - name of the preset to use
+-o=<outputFile> - full path to the file where to write an alignment
+-f=<parameterInputFile> - the name of the file with the list of parameters to use.
+Please note that -r and -f options cannot be used together. Alignment is done with either preset or a parameters from the file, but not both!
+

Align sequences from input.fasta file using Mafft web service with default settings, print alignment in Clustal format to console.

+

java -jar jabaws-min-client.jar -h=http://myhost.compbio.ac.uk:8080/jabaws -s=MafftWS -i=d:\input.fasta

+

Content of input.fasta file is show below (please note sequences has been trimmed for clarity)>Foobar
+ MTADGPRELLQLRAAVRHRPQDFVAWL
+ >Bar
+ MGDTTAGEMAVQRGLALHQ
+ QRHAEAAVLLQQASDAAPE
+ >Foofriend
+ MTADGPRELLQLRAAV

+

Align as in above example, but write output alignment in a file out.clustal, using parameters defined in prm.in file

+

java -jar jabaws-min-client.jar -h=http://myhost.compbio.ac.uk:8080/jabaws -s=MafftWS -i=d:\input.fasta -o=d:\out.clustal -f=prm.in

+

The content of the prm.in file is shown below --nofft
+ --noscore
+ --fastaparttree
+ --retree=10
+ --op=2.2

+

The format of the file is the same for all JABAWS web services. Parameters are specified in exactly the same way as for native executables - alignment programs like Mafft etc. So parameters which you can use with command line version of an alignment program can be used with JABAWS. Most of the settings controlling alignment process are supported, but the setting controlling output are not. This is due to the fact the output have to be handled by JABAWS, so must remain within its control. For a list of parameters supported by a web service see the next example. In prm.in parameters are separated by the new line, and name of the parameter is separated from its value with an equal sign. This format is constant no matter which JABAWS web service is used.
+ java -jar jabaws-min-client.jar -h=http://myhost.compbio.ac.uk:8080/jabaws -s=MafftWS -parameters

+

The same client can be used to access JABAWS on different hosts. Just point the client to the host you want to use by changing the value of -h key. For example you used -h=http://myhost.compbio.ac.uk:8080/jabaws server, now you want to use another server to -h=http://mylabserver.myuni.edu. This comes handy if your favorite server is off and you need to do the job yesterday.

+
+ + + +
+ + +
+ + + + + + + + diff --git a/website/man_configuration.html b/website/man_configuration.html new file mode 100644 index 0000000..5122e08 --- /dev/null +++ b/website/man_configuration.html @@ -0,0 +1,437 @@ + + + + + +Java Bioinformatics Analyses Web Services (JABAWS) Server Configuration manual + + + + + +
+ + +
+ + + +
+

JABAWS MANUAL

+ +

JABAWS Configuration

+ +

JABAWS Configuration

+

There are three parts of the system you can configure. The local +and the cluster engines, and the paths to the individual executables for +each engine. These settings are stored in configuration files +within the web application directory (for an overview, then take a +look at the war file content table).

+

Initially, JABAWS is configured with only the local engine + enabled, with job output written to directory called "jobsout" + within the web application itself. This means that JABAWS will work + out of the box, but may not be suitable for serving a whole lab or + a university.

+

Local Engine Configuration

+ +

The Local execution engine configuration is defined in the +properties file conf/Engine.local.properties. The supported +configuration settings are:
+ engine.local.enable=true - # +enable or disable local engine, valid values true | false
+ local.tmp.directory=D:\\clusterengine\\testoutput +- a directory to use for temporary files storage, optional, +defaults to java temporary directory
+ engine.local.thread.number=4 - +Number of threads for tasks execution (valid values between 1 and +2x cpu. Where x is a number of cores available in the system). +Optional defaults to the number of cores for core number <=4 and +number of cores-1 for greater core numbers.

+ +

If the local engine going to be heavily loaded (which is often the case if you do not have a cluster) it is a good idea to increase +the amount of memory available for the web application server. If +you are using Apache-Tomcat, then you can define its memory +settings in the JAVA_OPTS environment variable. To specify which +JVM to use for Apache-Tomcat, put the full path to the JRE +installation in the JAVA_HOME environment variable (We would +recommend using Sun Java Virtual Machine (JVM) in preference to +Open JDK). Below is an example of code which can be added to <tomcat_dir>/bin/setenv.sh script +to define which JVM to use and a memory settings for Tomcat server. +Tomcat server startup script (catalina.sh) will execute setenv.sh on each server start +automatically.
+ export +JAVA_HOME=/homes/ws-dev2/jdk1.6.0_17/
+ export JAVA_OPTS="-server -Xincgc -Xms512m -Xmx1024m"

+ +

Cluster Engine Configuration

+ +

Supported configuration settings:
+ engine.cluster.enable=true - # +enable or disable local engine true | false, defaults to +false
+ cluster.tmp.directory=/homes/clustengine/testoutput- +a directory to use for temporary files storage. The value must be +an absolute path to the temporary directory. Required. The value +must be different from what is defined for local engine. This +directory must be accessible from all cluster nodes.
+ For the cluster engine to work, the SGE_ROOT and LD_LIBRARY_PATH +environment variables have to be defined. They tell the cluster +engine where to find DRMAA libraries. These variables +should be defined when the web application server starts up, e.g.

+ +

SGE_ROOT=/gridware/sge
+ LD_LIBRARY_PATH=/gridware/sge/lib/lx24-amd64

+ +

Finally, do not forget to configure executables for the cluster +execution, they may be the same as for the local execution but may +be different. Please refer to the executable configuration section +for further details.

+ +

Executable Configuration

+ +

All the executable programs +are configured in conf/Executable.properties file. Each executable +is configured with a number of options. They are: local.X.bin.windows=<path to executable under windows +system, optional>
+ local.X.bin=<path to the executable under non-windows system, +optional>
+ cluster.X.bin=<path to the executable on the cluster, all +cluster nodes must see it, optional>
+ X.bin.env=<semicolon separated list of environment variables +for executable, use hash symbol as name value separator, +optional>
+ X.--aamatrix.path=<path to the directory containing +substitution matrices, optional>
+ X.presets.file=<path to the preset configuration file, optional +>
+ X.parameters.file=<path to the parameters configuration file, +optional>
+ X.limits.file=<path to the limits configuration file, +optional>
+ X.cluster.settings=<list of the cluster specific options, +optional>

+ +

Where X is either clustal, muscle, mafft, probcons or tcoffee.

+ +

Default JABAWS configuration includes path to local executables +to be run by the local engine only, all cluster related settings +are commented out, but they are there for you as example. Cluster +engine is disabled by default. To configure executable for cluster +execution un comment the X.cluster settings and change them +appropriately.

+

By default limits are set well in excess of what you may want to offer to the users outside your lab, to make sure that the tasks are never rejected. The default limit is 100000 sequences of 100000 letters on average for all of the JABA web services. You can adjust the limits according to your needs by editing conf/settings/<X>Limit.xml files.
+ After you have completed the editing your configuration may look like + this:local.mafft.bin.windows=
+ local.mafft.bin=binaries/mafft
+ cluster.mafft.bin=/homes/cengine/mafft
+ mafft.bin.env=MAFFT_BINARIES#/homes/cengine/mafft;FASTA_4_MAFFT#/bin/fasta34;
+ mafft.--aamatrix.path=binaries/matrices
+ mafft.presets.file=conf/settings/MafftPresets.xml
+ mafft.parameters.file=conf/settings/MafftParameters.xml
+ mafft.limits.file=conf/settings/MafftLimits.xml
+ mafft.cluster.settings=-q bigmem.q -l h_cpu=24:00:00 -l + h_vmem=6000M -l ram=6000M

+

Please not that relative paths must only be specified for the +files that reside inside web application directory, all other paths +must be supplied as absolute!

+ +

Furthermore, you should avoid using environment variables within the paths or options - since these will not be evaluated correctly. Instead, please explicitly +specify the absolute path to anything +normally evaluated from an environment variable at execution time.

+ +

If you are using JABAWS to submit jobs to the cluster (with +cluster engine enabled), executables must be available from all +cluster nodes the task can be sent to, also paths to the +executables on the cluster e.g. cluster.<exec_name>.bin must be +absolute.

+ +

Executables can be located anywhere in your system, they do not +have to reside on the server as long as the web application server +can access and execute them.

+ +

Cluster settings are treated as a black box, the system will +just pass whatever is specified in this line directly to the +cluster submission library. This is how DRMAA itself treats this +settings. More exactly DRMAA JobTemplate.setNativeSpecification() function will be called.

+ +

Defining Environment Variables for +Executables

+ +

Environment variables can be defined in property x.bin.env Where x is +one of five executables supported by JABAWS. Several environment +variables can be specified in the same line. For example.
+ mafft.bin.env=MAFFT_BINARIES#/homes/cengine/mafft;FASTA_4_MAFFT#/bin/fasta34;

+ +

The example above defines two environment variables with names +MAFFT-BINARIES and FASTA_4_MAFFT and values /homes/cengine/mafft +and /bin/fasta34 respectively. Semicolon is used as a separator +between different environment variables whereas hash is used as a +separator for name and value of the variable.

+ +

Configure JABAWS to Work +with Mafft

+ +

If you use default configuration you do not need to read any +further. The default configuration will work for you without any +changes, however, if you want to install Mafft yourself then there +is a couple of more steps to do.

+ +

Mafft executable needs to know the location of other files +supplied with Mafft. In addition some Mafft functions depends on +the fasta executable, which is not supplied with Mafft, but is a +separate package. Mafft needs to know the location of fasta34 +executable.

+ +

To let Mafft know where the other files from its package are +change the value of MAFFT-BINARIES environment variables. To let +Mafft know where is the fasta34 executable set the value of +FASTA_4_MAFFT environment variable to point to a location of +fasta34 program. The latter can be added to the PATH variable +instead. If you are using executables supplied with JABAWS, the +path to Mafft binaries would be like <relative path to web application +directory>/binaries/src/mafft/binaries and the path to +fasta34 binary would be <relative path +to web application +directory>/binaries/src/fasta34/fasta34. You can specify +the location of Mafft binaries as well as fasta34 program elsewhere +by providing an absolute path to them. All these settings are +defined in conf/Executable.properties file.

+

Limiting the size of the job accepted by JABAWS

+

JABAWS can be configured to reject excessively large tasks. This is useful if you operate JABAWS service for many users. By defining a maximum allowed task size you can provide an even service for all users and prevents waist of resources on the tasks too large to complete successfully. You can define the maximum number of sequences and the maximum average sequence length that JABAWS accepts for each JABA Web Service independently. +Furthermore, you can define different limits for different presets of the same web service.
+By default limits are set well in excess of what you may want to offer to the users outside your lab, to make sure that the tasks are never rejected. The default limit is 100000 sequences of 100000 letters on average for all of the JABA web services. You can adjust the limits according to your needs by editing conf/settings/<X>Limit.xml files.

+

Using a different version of the alignment program with JABAWS

+

JABAWS supplied with binaries and source code of the executables which version it supports. So normally you would not need to install your own executables. However, if you have a different version of an executable (e.g. an alignment program) which you prefer, you could use it as long as it supports all the functions JABAWS executable supported. This could be the case with more recent executable. If the options supported by your chosen executable is different when the standard JABAWS executable, than you need to edit ExecutableNameParamaters.xml  configuration file.

+

Load balancing

+

If your cluster is busy and have significant waiting times you can achieve a faster response by allowing the server machine to calculate small tasks and the reserve the cluster for bigger jobs. This works especially well if your server is a powerful machine with many CPUs. To do this you need to enable and configure both the cluster and the local engines. Once this is done decide on the maximum size of a task to be run on the server locally. Then, edit "# LocalEngineExecutionLimit #" preset in <ServiceName>Limits.xml file accordingly. JABAWS server then will balance the load according to the following rule: If the task size is smaller then the maximum task size for local engine, and the local engine has idle threads, then calculate task locally otherwise submit the task to the cluster.

+

Reviewing JABAWS configuration via web browser

+

Access to configuration files is prohibited to any unauthorized users by means of security constrain defined in web application descriptor file. There is a special user role called admin who can access these files. This comes handy if you would like to keep an eye on any of the task outputs stored in jobsout, or would like to view the configuration files. To access the configuration files add admin user into your application server. The way you do it depends on where you would like the user passwords to come from and your web application server. If you use Tomcat, then the simplest way is to use Tomcat Memory Realm which is linked to a plain text configuration file. To define the user in Tomcat server add an entry in conf/tomcat-user.xml file. <role rolename="admin"/>
+ <user username="admin" password="your password here " roles="admin"/>

+

Once this is done make sure the servlet that returns the web application directory listings is enabled. Look in the <tomcatroot>/conf/web.xml file for the following <param-name>listings</param-name>
+ <param-value>true</param-value>

+

The whole section that defines default listing servlet is below

+

<servlet>
+ <servlet-name>default</servlet-name>
+ <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
+ <init-param>
+ <param-name>debug</param-name>
+ <param-value>0</param-value>
+ </init-param>
+ <init-param>
+ <param-name>listings</param-name>
+ <param-value>true</param-value>
+ </init-param>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+

+

These listings are read only by default.

+

Testing JABA Web Services

+

You can use a command line client (part of the client only + package) to test your JABAWS installation as described here. If you downloaded a JABAWS + server package, you can use <your_jaba_context_name>/WEB-INF/lib/jaba-client.jar to test JABAWS installation as described in here. If you downloaded the source + code, then you could run a number of test suits defined in the + build.xml Apache Ant file.

+

JABAWS requests logging

+

Enable Tomcat log valve. To do this uncomment the following section of <tomcat_root>/conf/server.xml configuration file.

+

<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
+ prefix="localhost_access_log." suffix=".txt" pattern="common" resolveHosts="false"/>

+

The following information will be logged:

+ + + + + + + + + + + + + + + +
Remote IPDateMethod server_URL protocol HTTP status Response size in bytes
10.31.11.159[10/Feb/2010:16:51:32 +0000]"POST /jws2/MafftWS HTTP/1.1"2002067
+

Which can be processed in various programs for log analysis , such as WebAlizer, Analog, AWStats.

+

JABAWS internal logging

+

JABAWS can be configured to log what it is doing. This comes + handy if you would like to see who is using your web services or + need to chase some problems. JABAWS uses log4j to do the logging, + the example of log4j configuration is bundled with JABAWS war file. + You will find it in the /WEB-INF/classes/log4j.properties file. All the + lines in this file are commented out. The reason why the logging is + disabled by default it simple, log4j have to know the exact + location where the log files should be stored. This is not known up + until the deployment time. To enable the logging you need to + define logDir property in the log4j.properties and uncomment section of + the file which corresponds to your need. More information is given + in the log4j.properties file + itself. Restart the Tomcat or the JABAWS web application to apply + the settings.

+

After you have done this, assuming that you did not change the + log4j.properties file yourself, you should see the application log + file called activity.log. The + amount of information logged can be adjusted using different + logging levels, it is reduced in the following order of log levels + TRACE, DEBUG, INFO, WARN, ERROR, FATAL.

+

If you would like to know who is using your services, you might + want to enable Tomcat request + logging.

+

Monitoring JABAWS

+

JABAWS stores cluster task ids for all tasks which were run on the cluster. Using cluster ids the detailed statistics can be extracted from cluster accounting system. Due to the fact that each cluster supported by JABAWS have different accounting system it was not possible to provide ready to use statistics.
+ For the local execution the starting and finishing time in nano seconds can be found in STARTED and FINISHED files respectively. In time we will provide the tools to extract execution time statistics, so keep the content of your working directory ready!

+

JABAWS War File Content

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DirectoryContent description
conf/contains configuration files such as Executable.properties, + Engine.local.properties, Engine.cluster.properties
conf/settingsContains individual executable description files. In particular + XXXParameters.xml, XXXPresets.xml, XXXLimits.xml where XXX is the + name of the executable
jobsout/Contains directories generated when running an individual executable. E.g. input and output files and some other task + related data. (optional)
binaries/Directory contains native executables - programs, + windows binaries (optional)
binaries/srcContains source of native executables and Linux i386 + binaries.
binaries/matricesSubstitution matrices +
WEB-INFWeb application descriptor
WEB-INF/libWeb application libraries
WEB-INF/classeslog4j.properties - log configuration file (optional)
Help Pages
/help pages, index.html is the starting page
dm_javadocjavadoc for JABAWS client (the link is available from How To + pages)
prog_docsdocumentation for programs that JABAWS uses
imagesimages referenced by html pages
+

 

+
+ + +
+ + +
+ + + + + + + + diff --git a/website/man_dev.html b/website/man_dev.html new file mode 100644 index 0000000..73dee08 --- /dev/null +++ b/website/man_dev.html @@ -0,0 +1,359 @@ + + + + + +Java Bioinformatics Analyses Web Services (JABAWS) client developers manual + + + + + +
+ + +
+ + + +
+

JABAWS MANUAL

+ +

Using JABAWS From Your Program

+ +

Web services functions overview

+

All JABA multiple sequence alignment web services comply to the same interface, thus the function described below are available from all the services.

+

Functions for initiating the alignment String id = align(List<FastaSequence> list)
+ String id = customAlign(List<FastaSequence> sequenceList, List<Option> optionList)
+ String id = presetAlign(List<FastaSequence> sequenceList, Preset preset)

+

Functions pertaining to job monitoring and control
+ JobStatus status = getJobStatus(String id)
+ Alignment al = getResult(String id)
+ boolean cancelled = cancelJob(String id)
+ ChunkHolder chunk = pullExecStatistics(String id, long marker)

+

Functions relating to service features discovery
+ RunnerConfig rc = getRunnerOptions()
+ Limit limit = getLimit(String name)
+ LimitsManager lm = getLimits()
+ PresetManager pm = getPresets()

+

Please refer to a data model javadoc for a detailed description of each methods.

+

Structure of the template command line client

+ + + + + + + + + + + + + + + + + + + + + +
PackagesClasses and Interfaces
compbio.data.msa MsaWS the interface for all multiple sequence alignment web services
compbio.data.sequenceJABAWS data types
compbio.metadataJABAWS meta data types
compbio.ws.clientJABAWS command line client
+

Additional utility libraries this client depend upon is the compbio-util-1.3.jar and compbio-annotation-1.0.jar.
+ Please refer to a data model javadoc for a detailed description of each class and its methods.

+

Connecting to JABAWS

+

For a complete working example of JABAWS command line client please see compbio.ws.client.Jws2Client class. JABAWS command line client source code is available from the download page. Please note that for now all the examples are in Java other languages will follow given a sufficient demand.

+

Download a binary JABAWS client. Add the client to the class path. The following code excerpt will connect your program to Clustal web service deployed in the University of Dundee.

+

import java.net.URL;
+ import javax.xml.namespace.QName;
+ import javax.xml.ws.Service;
+ ...............
+ 1) String qualifiedName = "http://msa.data.compbio/01/01/2010/";
+ 2) URL url = new URL("http://www.compbio.dundee.ac.uk/jabaws/ClustalWS?wsdl");
+ 3) QName qname = new QName(, "ClustalWS");
+ 4) Service serv = Service.create(url, qname);
+ 5) MsaWS msaws = serv.getPort(new QName(qualifiedName, "ClustalWSPort"), + MsaWS.class);

+

Line 1 makes a qualified name for JABA web services.
+ Line 2 + constructs the URL to the web services WSDL.
+ Line 3 makes a qualified name instance for Clustal JABA web service.
+ Line 4 creates a service instance.
+ Line 5 makes a connection to the server.

+

A more generic connection method would look like this

+

import java.net.URL;
+ import javax.xml.namespace.QName;
+ import javax.xml.ws.Service;
+ import compbio.ws.client.Services
+ ..............
+ String qualifiedServiceName = "http://msa.data.compbio/01/01/2010/";
+ String host = "http://www.compbio.dundee.ac.uk/jabaws";
+ // In real life the service name can come from args
+ Services clustal = Services.ClustalWS;
+ URL url = new URL(host + "/" + clustal.toString() + "?wsdl");
+ QName qname = new QName(qualifiedServiceName, clustal.toString());
+ Service serv = Service.create(url, qname);
+ MsaWS msaws = serv.getPort(new QName(qualifiedServiceName, clustal
+ + "Port"), MsaWS.class);

+

Where Services is enumeration of JABAWS web services. All JABAWS multiple sequence alignment methods confirm to MsaWS specification, thus from the caller point of view all JABAWS web services can be represented by MsaWS interface. The full documentation of MsaWS functions is available from the javadoc.

+

Valid JABAWS service names and WSDL files

+
    +
  • ClustalWS (http://www.compbio.dundee.ac.uk/jabaws/ClustalWS?wsdl)
  • +
  • MuscleWS (http://www.compbio.dundee.ac.uk/jabaws/MuscleWS?wsdl)
  • +
  • MafftWS (http://www.compbio.dundee.ac.uk/jabaws/MafftWS?wsdl)
  • +
  • TcoffeeWS (http://www.compbio.dundee.ac.uk/jabaws/TcoffeeWS?wsdl)
  • +
  • ProbconsWS (http://www.compbio.dundee.ac.uk/jabaws/ProbconsWS?wsdl)
  • +
+

Aligning sequences

+

Given that msaws is web service proxy, created as described in "Connecting to JABAWS" section, the actual alignment can be obtained as follows:

+

1) List<FastaSequence> fastalist = SequenceUtil.readFasta(new FileInputStream(file));
+ 2) String jobId = msaws.align(fastalist);
+ 3) Alignment alignment = msaws.getResult(jobId);

+

Line one loads FASTA sequence from the file
+ Line two submits them to web service represented by msaws proxy
+ Line three retrieves the alignment from a web service. This line will block the execution until the result is available. Use this with caution. In general, you should make sure that the calculation has been completed before attempting retrieving results. This is to avoid keeping the connection to the server on hold for a prolonged periods of time. While this may be ok with your local server, our public server (www.compbio.dundee.ac.uk/jabaws) will not let you hold the connection for longer than 10 minutes. This is done to prevent excessive load on the server. The next section describes how to check the status of the calculation.
+ Methods and classes mentioned in the excerpt are available from the JABAWS client library.

+

Checking the status of the calculation

+

You may have noticed that there was no pause between submitting the job and retrieving of the results. This is because getResult(jobId) method block the processing until the calculation is completed. However, taking into account that the connection holds server resources, our public server (www.compbio.dundee.ac.uk/jabaws) is configured to reset the connection after 10 minutes of waiting. To work around the connection reset you are encouraged to check whether the calculation has been completed before accessing the results. You can do it like this:

+

while (msaws.getJobStatus(jobId) != JobStatus.FINISHED) {
+     Thread.sleep(2000); // wait two seconds, then recheck the status
+ }

+

Aligning with presets

+

1) PresetManager presetman = msaws.getPresets();
+ 2) Preset preset = presetman.getPresetByName(presetName);
+ 3) List<FastaSequence> fastalist = SequenceUtil.readFasta(new FileInputStream(file));
+ 4) String jobId = msaws.presetAlign(fastalist, preset);
+ 5) Alignment alignment = msaws.getResult(jobId);

+

Line one obtains the lists of presets supported by a web service.
+ Line two return a particular Preset + by its name
+ Lines three to five are doing the same job as in the first aligning sequences example.

+

Aligning with custom parameters

+

1) RunnerConfig options = msaws.getRunnerOptions();
+ 2) Argument matrix = options.getArgument("MATRIX");
+ 3) matrix.setValue("PAM300");
+ 4) Argument gapopenpenalty = options.getArgument("GAPOPEN");
+ 5) gapopenpenalty.setValue("20");
+ 6) List<Argument> arguments = new ArrayList<Argument>();
+ 7) arguments.add(matrix); + arguments.add(gapopenpenalty);
+ 8) List<FastaSequence> fastalist = SequenceUtil.readFasta(new FileInputStream(file));
+ 9) String jobId = msaws.customAlign(fastalist, arguments);
+ 10) Alignment alignment = msaws.getResult(jobId);

+

Line one obtains the RunnerConfig object that holds information on supported parameters and their values
+ Line two retrieve a particular parameter from the holder by its name
+ Lines three sets a value to this parameter which will be used in the calculation.
+ Line four and five do the same but for another parameter
+ Line 6 makes a List to hold the parameters
+ Line seven puts the parameters into that list
+ Line eight + and ten is the same as in previous examples
+ Line nine submit an alignment request with the sequences and the parameters
+ The names of all the parameters supported by a web service e.g. "PAM300" can be obtained using options.getArguments() method. Further details on the methods available from RunnerConfig object are available from the javadoc.

+

Writing alignments to a file

+

There is a utility method in the client library that does exactly that.

+

Alignment alignment = align(...)
+ FileOutputStream outStream = new FileOutputStream(file);
+ ClustalAlignmentUtil.writeClustalAlignment(outStream, align);

+

A complete client example

+

Finally, a complete example of the program that connects to JABAWS Clustal service and aligns sequences using one of the Clustal web service preset. Three is also a PDF version of this example with syntax highlighted. The text comments are commented by block style comments e.g. /* comment */, the alternatives given in the code are line commented // comment. You may want to remove line style comments to test alternatives of the functions. All you need for this to work is a JABAWS binary client. Please make sure that the client is in the Java class path before running this example.

+
+import java.io.ByteArrayInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URL;
+import java.util.List;
+
+import javax.xml.namespace.QName;
+import javax.xml.ws.Service;
+
+import compbio.data.msa.MsaWS;
+import compbio.data.sequence.Alignment;
+import compbio.data.sequence.FastaSequence;
+import compbio.data.sequence.SequenceUtil;
+import compbio.metadata.JobSubmissionException;
+import compbio.metadata.LimitExceededException;
+import compbio.metadata.Preset;
+import compbio.metadata.PresetManager;
+import compbio.metadata.ResultNotAvailableException;
+import compbio.metadata.UnsupportedRuntimeException;
+import compbio.metadata.WrongParameterException;
+
+public class Example {
+
+	/*
+	 * Input sequences for alignment
+	 */
+	static final String input = ">Foo\r\n"
+			+ "MTADGPRELLQLRAAVRHRPQDFVAWLMLADAELGMGDTTAGEMAVQRGLALHPGHPEAVARLGR"
+			+ "VRWTQQRHAEAAVLLQQASDAAPEHPGIALWLGHALEDAGQAEAAAAAYTRAHQLLPEEPYITAQ"
+			+ "LLNWRRRLCDWRALDVLSAQVRAAVAQGVGAVEPFAFLSEDASAAEQLACARTRAQAIAASVRPL"
+			+ "APTRVRSKGPLRVGFVSNGFGAHPTGLLTVALFEALQRRQPDLQMHLFATSGDDGSTLRTRLAQA"
+			+ "STLHDVTALGHLATAKHIRHHGIDLLFDLRGWGGGGRPEVFALRPAPVQVNWLAYPGTSGAPWMD"
+			+ "YVLGDAFALPPALEPFYSEHVLRLQGAFQPSDTSRVVAEPPSRTQCGLPEQGVVLCCFNNSYKLN"
+			+ "PQSMARMLAVLREVPDSVLWLLSGPGEADARLRAFAHAQGVDAQRLVFMPKLPHPQYLARYRHAD"
+			+ "LFLDTHPYNAHTTASDALWTGCPVLTTPGETFAARVAGSLNHHLGLDEMNVADDAAFVAKAVALAS"
+			+ "DPAALTALHARVDVLRRESGVFEMDGFADDFGALLQALARRHGWLGI\r\n"
+			+ "\r\n"
+			+ ">Bar\r\n"
+			+ "MGDTTAGEMAVQRGLALHQQRHAEAAVLLQQASDAAPEHPGIALWLHALEDAGQAEAAAAYTRAH"
+			+ "QLLPEEPYITAQLLNAVAQGVGAVEPFAFLSEDASAAESVRPLAPTRVRSKGPLRVGFVSNGFGA"
+			+ "HPTGLLTVALFEALQRRQPDLQMHLFATSGDDGSTLRTRLAQASTLHDVTALGHLATAKHIRHHG"
+			+ "IDLLFDLRGWGGGGRPEVFALRPAPVQVNWLAYPGTSGAPWMDYVLGDAFALPPALEPFYSEHVL"
+			+ "RLQGAFQPSDTSRVVAEPPSRTQCGLPEQGVVLCCFNNSYKLNPQSMARMLAVLREVPDSVLWLL"
+			+ "SGPGEADARLRAFAHAQGVDAQRLVFMPKLPHPQYLARYRHADLFLDTHPYNAHTTASDALWTGC"
+			+ "PVLTTPGETFAARVAGSLNHHLGLDEMNVADDAAFVAKAVALASDPAALTALHARVDVLRRESGV"
+			+ "FEMDGFADDFGALLQALARRHGWLGI\r\n"
+			+ "\r\n"
+			+ ">Friends\r\n"
+			+ "MTADGPRELLQLRAAVRHRPQDVAWLMLADAELGMGDTTAGEMAVQRGLALHPGHPEAVARLGRV"
+			+ "RWTQQRHAEAAVLLQQASDAAPEHPGIALWLGHALEDHQLLPEEPYITAQLDVLSAQVRAAVAQG"
+			+ "VGAVEPFAFLSEDASAAEQLACARTRAQAIAASVRPLAPTRVRSKGPLRVGFVSNGFGAHPTGLL"
+			+ "TVALFEALQRRQPDLQMHLFATSGDDGSTLRTRLAQASTLHDVTALGHLATAKHIRHHGIDLLFD"
+			+ "LRGWGGGGRPEVFALRPAPVQVNWLAYPGTSGAPWMDYVLGDAFALPPALEPFYSEHVLRLQGAF"
+			+ "QPSDTSRVVAEPPSRTQCGLPEQGVVLCCFNNSYKLNPQSMARMLAVLREVPDSVLWLLSGPGEA"
+			+ "DARLRAFAHAQGVDAQRLVFMPKLPHPQYLARYRHADLFLDTHPYNAHTTASDALWTGCPVLTTP"
+			+ "GETFAARVAGSLNHHLGLDEMNVADDAAFVAKAVALASDPAALTALHARVDVLRRESI";
+
+	public static void main(String[] args) throws UnsupportedRuntimeException,
+			LimitExceededException, JobSubmissionException,
+			WrongParameterException, FileNotFoundException, IOException,
+			ResultNotAvailableException, InterruptedException {
+
+		String qualifiedServiceName = "http://msa.data.compbio/01/01/2010/";
+
+		/* Make a URL pointing to web service WSDL */
+		URL url = new URL(
+				"http://www.compbio.dundee.ac.uk/jabaws/ClustalWS?wsdl");
+
+		/*
+		 * If you are making a client that connects to different web services
+		 * you can use something like this:
+		 */
+		// URL url = new URL(host + "/" + Services.ClustalWS.toString() +
+		// "?wsdl");
+
+		QName qname = new QName(qualifiedServiceName, "ClustalWS");
+		Service serv = Service.create(url, qname);
+		/*
+		 * Multiple sequence alignment interface for Clustal web service
+		 * instance
+		 */
+		MsaWS msaws = serv.getPort(new QName(qualifiedServiceName, "ClustalWS"
+				+ "Port"), MsaWS.class);
+
+		/* Get the list of available presets */
+		PresetManager presetman = msaws.getPresets();
+
+		/* Get the Preset object by preset name */
+		Preset preset = presetman
+				.getPresetByName("Disable gap weighting (Speed-oriented)");
+
+		/*
+		 * Load sequences in FASTA format from the file You can use something
+		 * like new FileInputStream(<filename>) to load sequence from the file
+		 */
+		List<FastaSequence> fastalist = SequenceUtil
+				.readFasta(new ByteArrayInputStream(input.getBytes()));
+
+		/*
+		 * Submit loaded sequences for an alignment using preset. The job
+		 * identifier is returned by this method, you can retrieve the results
+		 * with it sometime later.
+		 */
+		String jobId = msaws.presetAlign(fastalist, preset);
+
+		/* This method will block for the duration of the calculation */
+		Alignment alignment = msaws.getResult(jobId);
+
+		/*
+		 * This is a better way of obtaining results, it does not involve
+		 * holding the connection open for the duration of the calculation,
+		 * Besides, as the University of Dundee public server will reset the
+		 * connection after 10 minutes of idling, this is the only way to obtain
+		 * the results of long running task from our public server.
+		 */
+		// while (msaws.getJobStatus(jobId) != JobStatus.FINISHED) {
+		// Thread.sleep(1000); // wait a second, then recheck the status
+		// }
+
+		/* Output the alignment to standard out */
+		System.out.println(alignment);
+
+		// Alternatively, you can record retrieved alignment into the file in
+		// ClustalW format
+
+		// ClustalAlignmentUtil.writeClustalAlignment(new FileOutputStream(
+		// "output.al"), alignment);
+
+	}
+}
+
+For a more detailed description of all available types and their functions please refer to the data model javadoc. +

Building web services artifacts

+

JABAWS are the standard JAX-WS SOAP web services, which are WS-I basic profile compatible. This means that you could use whatever tool your language has to work with web services. Below is how you can generate portable artifacts to work with JABAWS from Java. However, if programming in Java we recommend using our client library as it provides a handful of useful methods in addition to plain data types.

+

wsimport -keep http://www.compbio.dundee.ac.uk/jabaws/ClustalWS?wsdl

+
+ + + +
+ + +
+ + + + + + + + diff --git a/website/man_servervm.html b/website/man_servervm.html new file mode 100644 index 0000000..66fc6c4 --- /dev/null +++ b/website/man_servervm.html @@ -0,0 +1,177 @@ + + + + + +Java Bioinformatics Analyses Web Services (JABAWS) Server Virtual Appliance Manual + + + + + +
+ + +
+ + + +
+

JABAWS MANUAL

+ +

JABAWS Server Virtual Appliance

+ + +

Troubleshooting

+ +

What is the JABAWS Server Virtual Appliance?

+

The JABAWS Virtual Appliance is a +way to run JABAWS server locally without the need to connect to the internet or configure JABAWS. +What the appliance provides is a 'virtual server machine' (or more simply - virtual machine or VM), running an installation of the JABAWS +Web Application Archive (WAR) on TurnKey Linux. Once this has started up, it displays a message indicating the IP address of the JABAWS server, allowing any JABAWS client (such as Jalview or the JABAWS command line client) to connect to it.
+You can run the appliance with freely available programs such as VMWare Player or +Oracle VirtualBox 3.2.x, but you will need to install them first. We have tested the JABAWS appliance +with VMware Player v 3.1.2 on Windows and Linux, and VirtualBox v. 3.2.12 on Windows, Linux and Mac. + However, you are not limited to these virtualization systems and can use the JABAWS appliance with any commercial alternative.

+

When to use the JABAWS Virtual Appliance

+

The appliance best suits users who would like to use the JABA web services locally. This might be because they do want to access +systems over an internet or local intranet connection, or alternately, want to keep their data private. It is also +the recommended option for users who want to install JABAWS on Windows, which does not support all the bioinformatics programs that JABAWS can run. +
Since the appliance is a self contained unit of software, it is also an attractive option for Linux, UNIX or Mac users wishing to set up JABAWS services quickly.

+

When not to use the JABAWS Virtual Appliance

+For servers that will be used heavily, we recommend that a JABAWS Server WAR distribution is deployed, rather than the Virtual Appliance version of JABAWS. +This is because the JABAWS appliance is pre-configured to use only 1 CPU and 512M of memory +(where the minimum amount of memory required for a JABAWS server is about 378M), which is unlikely to be sufficient for heavy computation. +It is possible to reconfigure the virtual appliance so it uses more computation resources, +but for most production environments, the JABAWS WAR distribution will be more easy to deploy and tune to take advantage of the resources available.

+ +

How to install VMWare Player or VirtualBox

+

Please see the VMware Player +and Oracle VirtualBox web sites for up to date instructions and downloads.

+ +

VMware Player appliance configuration

+

The free VMware Player can be used to run the JABAWS services from the Windows and Linux host operating systems, there is no support for Mac at the time of writing (December 2010). +However, VMware Fusion, a commercial VMware product, offers virtual machine support for Mac computers too.

+

To run the JABAWS server on VMware player, unpack the JABAWS VM into one of the folders on your local hard drive. Open VMware Player, click "Open Virtual Machine" and point the Player to the location of the JABAWS, then choose the JABAWS.vmx file to open an appliance.

+

When you play the machine for the first time the Player might ask you whether "This virtual machine may have been moved or copied.", say that you have copied it. That is all.

+

VirtualBox appliance configuration

+

VirtualBox can be used to run JABAWS services from Windows, Linux, Solaris or Mac host operating systems. Use the VitualBox "Import Appliance" option to import the JABAWS. Please bear in mind that to benefit from multiple CPU support under the VirtualBox software you need to enable hardware virtualization extensions, such as Intel Virtualization VT-x or AMD-V support in the BIOS of your computer. Unfortunately, we were unable to find a reliable way to do it on Mac, so some Macs running VirtualBox will be limited to one CPU only, irrespective of the number of CPUs of the host machine.

+

We found that, by default, virtualization extensions are enabled in VirtualBox irrespective of whether your computer supports them. You will get the VERR_VMX_MSR_LOCKED_OR_DISABLED exception if your computer does not support the extensions or their support is disabled. Just deselect the checkboxes shown on the screen shot below to solve the problem.

+

VirtualBox JABAWS VM configuration screen shot displaying virtualization settings.

+

VT-x extension on VirtualBox

+

JABAWS Appliance details

+

By default, the JABAWS virtual appliance is configured with 512M of memory and 1 CPU, but you are free to change these settings. If you have more than one CPU or CPU core on your computer you can make them available for the JABAWS virtual machine by editing virtual machine settings. Please bear in mind that more CPU power will not make a single calculation go faster, but it will enable the VM to do calculations in parallel. Similarly, you can add more memory to the virtual machine. More memory lets your VM deal with larger tasks, e.g. work with large alignments.

+

The VMware Player screen shot below displays JABAWS VM CPU settings.

+

vmware cpu settings

+ +

JABAWS appliance configuration:

+

VMware info
+ - CPUs : 1
+ - RAM : 512 MB
+ - Networking : Host only (the VM has no access to the outside network, nothing from the outside network can access the VM)
+ - Hard disk : 20 GB (expanding)
+ - VMware tools : Installed

+

OS info
+ - OS : TurnKey Linux, based on Ubuntu 8.0.4 JEOS (Just-Enough-Operation-System)
+ - Installation : Oracle Java 6, Tomcat 6, JABAWS v. 1.0
+ - Hostname : tomcat
+ - IPv4 address : dhcp
+ - IPv6 address : auto
+ - DNS name : none
+ - Name server : dhcp
+ - Route : dhcp
+ - Keyboard : US_intl

+

Login credentials
+ - Root password: jabaws

+

Services

+
    +
  • Default virtual console Alt+F7
  • +
  • Tomcat web server.
    + Access: http://VM_IP
  • +
  • JABAWS URL: http://VM_IP/jabaws
  • +
  • Web Shell
    + Access: https://VM_IP:12320/
  • +
  • Webmean
    + Access: https://VM_IP:12321/
  • +
  • SSH/SFTP
    + Access: root@VM_IP
  • +
+

Where VM_IP is the VM IP address. Under VMware Player host only networking, the first VM may have 192.168.227.128 IP address. Under VirtualBox host only networking, first VM may have 192.168.56.101 IP address.

+

Configuring Jalview to work with your JABAWS VM

+

After booting the JABAWS VM, you should see similar screen, however, the IP address of your VM may be different. To enable Jalview to work with your JABAWS appliance you need to go to Jalview->Tools->Preferences->Web Services -> New Service URL, and add JABAWS URL into the box provided. For more information please refer to Jalview help pages.

+

JABAWS welcome screen

+

If you click on Advanced Menu, you will see the configuration console, similar to the one below.

+

JABAWS welcome screen

+

If you need to configure a static IP address the configuration console will help you with this. Shutting down the VM is best from the configuration console as well.

+

VM Network Settings

+

By default the JABAWS VM is configured to use host-only networking. This means that the host can communicate with the VM via a network, but no other machines can. Similarly, the VM cannot communicate with any other computers apart from the host. If you want to connect to the Internet from the VM, configure your VM to use NAT network. However, you will not be able to connect to the VM from the host in such case. If you want to be able to connect to your VM and let VM connect to the internet at the same time you would have to use a Bridged network. In such a case you would have to configure the VM IP address manually (unless of course your network has a DHCP server to do that)

+

VirtualBox fails to open the VM due to VERR_VMX_MSR_LOCKED_OR_DISABLED exception

+

VERR_VMX_MSR_LOCKED_OR_DISABLED exception means that Intel Virtualization technology is disabled or not supported by your computer. If you have such a problem, please make sure you have configured the JABAWS VM with 1 CPU and disabled VT-X extensions. Alternatively you can enable virtualization extensions ion from the BIOS of your computer. Unfortunately, we cannot give you exact instructions on how to do this, as this would depend on your computer BIOS manufacturer. For MACs it may not be possible at all.

+

VirtualBox 4.0.0 fails to import the VM due to VBOX_E_INVALID_OBJECT_STATE exception

+

VirtualBox version 4.x.x is not compatible with JABAWS virtual appliance. Please download the previous version of VirtualBox 3.2.12 to use with JABAWS VA.

+

VMWare Player fails to open the VM with "Fail to query source for information" exception

+

At the time of writing, the latest version of VMware Player 3.1.2 supported only a legacy OVF version 0.9. Whereas OVF packaged with JABAWS VM is version 1.0. Please use VMX - VMware specific configuration file with all VMware products.

+
+ + + +
+ + +
+ + + + + + + + diff --git a/website/man_serverwar.html b/website/man_serverwar.html new file mode 100644 index 0000000..dc994bc --- /dev/null +++ b/website/man_serverwar.html @@ -0,0 +1,265 @@ + + + + + +Java Bioinformatics Analyses Web Services (JABAWS) Server Web Aplication aRchive manual + + + + + +
+ + +
+ + + +
+

JABAWS MANUAL

+ +

JABAWS Server Web Application aRchive (WAR)

+ +

Troubleshooting

+ +

System Requirements

+

JABAWS requires a Java web application server compliant with +version 2.4 of the Java Servlet specification, and a Java 6 runtime +environment. We recommend using an official Oracle Java 6 runtime +environment, and Apache-Tomcat web application server version 6, but other versions may work as well.
Please Note: The JABAWS WAR is not generally compatible with older Mac systems based on the PowerPC architecture, since Java 1.6 is not available to run JABAWS.

+ +

JABAWS Web Application aRchive can run on any host operating system that supports Java 1.6. However JABAWS depends on a number of third party programs which are not available for all operating systems. In particular, only Clustal and Muscle are currently available for MS Windows platform. + +

+

JABAWS comes with pre-compiled MS Windows and Linux IA32 binaries, as well as the source code and build scripts necessary to recompile them.

+

To run JABAWS on the cluster you must have shared disk space accessible from all cluster nodes.

+

Installing the JABAWS WAR file

+

JABAWS is distributed as a web application archive (WAR). To +deploy JABAWS in Apache-Tomcat - simply drop the war file into the +webapps directory of a running +Tomcat, and it will do the rest. If you used this deployment procedure, do not remove the jabaws WAR file, otherwise Tomcat will undeploy your application! The context path for your deployed application will be the same as the name of the war file. For example, assuming the Tomcat server is running on the localhost:8080 and jaba.war file is put into the <tomcat server root>/webapps directory, the deployed application from the jaba.war file then can be accessed by this URL http://localhost:8080/jaba.

+

For any other web application + server, please follow your server's specific deployment procedure + for 'WAR' files. If you install JABAWS on a MS Windows machine, then + at this point your JABAWS installation will already be up and + running, and you can try its services out as described here. If you install JABAWS on Linux you will need to set an executable flag for binaries. This is described here. If your host operating system is different from Windows or Linux then read on.

+

Preparing executables for use with JABAWS

+ +

JABAWS's web services use command line programs to do +the actual analysis, so it must have access to programs +which can be executed on your platform. The native executables +bundled with JABAWS for Windows (32-bit) and Linux (i386, 32-bit) should be +OK for those systems. The source code for these +programs is also provided so you can recompile for your own +architecture and exploit any optimizations that your system can +provide. Alternately, if you have already got binaries on your +system, then you can simply change the paths in JABAWS's +configuration files so these are used instead.

+ +

Using the pre-compiled i386 binaries on Linux

+ +

Before the binaries that are bundled with JABAWS can be used, +they must first be made executable using the provided 'setexecflag.sh' script:

+ +
    +
  1. cd to <webapplicationpath>/binaries/src
  2. + +
  3. run sh setexecflag.sh
  4. + +
  5. Make sure binaries supplied work under your OS.
    + For this run each binary, without any command line options or +input files. If you see an error message complaining about missing +libraries or other problems, then you probably need to recompile the binaries.
  6. + +
  7. Restart the Tomcat.
  8. +
+ +That's it! JABAWS should work at this point. Try it out using the JABAWS test client. If not, +read on... or have a look at deploying on Tomcat tips.
+ Note: You may want to enable logging, as described here.
+ + +

Recompiling the bundled +programs for your system

+ +

If you have a fully equipped build environment on your +(POSIX-like) system, then you should be able to recompile the +programs from the source distributions which are included +in the JABAWS war file. A script called 'compilebin.sh' is provided +to automate this task.

+ +
    +
  1. In a terminal window, change the working directory to binaries/src
  2. + +
  3. execute the compilebin.sh +script,
    + either use: chmod +x compilebin.sh; +compilebin.sh > compilebin.out;
    + or: sh compilebin.sh > +compilebin.out
  4. + +
  5. Now run sh setexecflag.sh
    + If any of the binaries was not recompiled, then a 'file not found' +error will be raised.
  6. + +
  7. Finally, restart your Tomcat server (or JABAWS application only), and test JABAWS to +check that it can use the new binaries.
  8. +
+ +

If you couldn't compile everything, then it may be that your system does +not have all the tools required for compiling the programs. At the very +least check that you have gcc, g++ and make installed in your +system. If not install these packages and repeat the compilation +steps again. You should also review the compilebin.sh output - +which was redirected to compilebin.out, and any errors output to +the terminal. Finally, try obtaining the pre +compiled binaries for your OS.

+ +

Reuse the binaries that are +already in your system

+ +

If you would like to use the binaries you already have then you +just need to let JABAWS know there they are. To do this, edit: +conf/Executable.properties

+

When specifying paths to executables that already exist on your system, make sure you provide an absolute path, or one relative to the JABAWS directory inside webapps. For example, the default path for clustalw is defined +aslocal.clustalw.bin=binaries/src/clustalw/src/clustalw2 +Alternatively, instead of changing Executable.properties you could also replace +the executables bundled with JABAWS with the ones that you have, or make symbolic links to them. +Then the default configuration will work for you. More information +about the +Executable.properties file is given in the JABAWS Configuration chapter.

+ +

Obtaining alignment +programs for your operating system

+ +

You could search for pre-packaged compiled executable in your +system package repository or alternately, download pre-compiled +binaries from each alignment program's home page. Then, either +replace the executables supplied with the downloaded ones, or +modify the paths in executable.properties as described above. Below are some suggestions on where you may be able to get the binaries for your system.

+ +

Testing JABAWS Server

+

First of all make sure that Tomcat server is started successfully. If this was the case, then you should see JABAWS home page when you navigate to your Tomcat JABAWS context path e.g. http://myhost.compbio.ac.uk:8080/jabawsIf you see it, then it is time to make sure that web services are working too. Assuming that you have unpacked/deployed JABAWS from the server war file, you should be able to navigate to the test program which can be found in <webapplicationpath>/WEB-INF/lib/jabaws-client.jar file. To run the tests type: java -jar jabaws-client.jar -h=<Your web application server host name, port and JABAWS context path>

+

For example to test all JABAWS web services on host myhost.compbio.ac.uk type:

+

java -jar jabaws-client.jar -h=http://myhost.compbio.ac.uk:8080/jabaws

+

You can choose a particular web server using -s option like this java -jar jabaws-client.jar -h=http://myhost.compbio.ac.uk:8080/jabaws -s=ClustalWS This command line assumes that java executable is in your path and jabaws-client.jar is located in the current directory.

+

An example of the report testing tool produces for operating web service looks like this:

+

Connecting to service MuscleWS on http://myhost.compbio.ac.uk:8080/jabaws ... OK
+ Testing alignment with default parameters:
+ Queering job status...OK
+ Retrieving results...OK
+ Testing alignment with presets:
+ Aligning with preset 'Protein alignment(Fastest speed)'... OK
+ Aligning with preset 'Nucleotide alignment(Fastest speed)'... OK
+ Aligning with preset 'Huge alignments (speed-oriented)'... OK
+ Queering presets...OK
+ Queering Parameters...OK
+ Queering Limits...OK
+ Queering Local Engine Limits...OK
+ Check is completed service MuscleWS IS WORKING
An example of the response of a web service which is deployed but is not operating is below:

+

Connecting to service ProbconsWS on http://localhost:8080/ws ... OK
+ Testing alignment with default parameters:FAILED
+ Service ProbconsWS IS NOT FUNCTIONAL
If the web server did not respond the message looks like following: Connecting to service TcoffeeWS on http://localhost:8080/ws ... FAILED

+

Running many JABAWS instances on the same server

+

JABAWS is supplied as a Web Application aRchive which can be dealt with as any other web applications. So it is perfectly possible to run two JABAWS instances from the same server. Just make two different contexts on your application server and unpack JABAWS in both of them. For example if your server name is http://www.align.ac.uk, and the context names are public and private. Than one group of users could be given a URL http://www.align.ac.uk/public and another http://www.align.ac.uk/private. These contexts will be served by two independent JABAWS instances, and could be configured differently. If you keep local engine enabled, make sure you reduce the number of threads local engine is allowed to use to avoid overloading the server. Alternatively two completely separate web application server instances (e.g. Apache-Tomcat) could be used. This will give you a better resilience and more flexibility in memory settings.

+

JABAWS on a single server

+

You can run JABAWS on a single server. Obviously the capacity will be limited, but may be sufficient for a small lab. Installed on a single server, JABAWS executes tasks in parallel, so the more cores the server has the more requests it will be able to handle.

+

JABAWS supported cluster batch management systems

+

JABAWS uses DRMAA v. 1.0 library to send and manage jobs on the cluster. DRMAA supports many different cluster job management systems. Namely Sun Grid Engine, Condor, PBS, GridWay, Globus 2/4, PBSPro, LSF. For up to date information please consult DRMAA web site. We found that DRMAA implementation differ from platform to platform and were trying to use only the basic functions. We have only tested JABAWS on Sun Grid Engine v 6.2. Please let use know if you have any experience of running JABAWS on other platforms.

+

Manually deploying JABAWS application on Apache-Tomcat

+

To stop Tomcat from automatically undeploying your application if the war file is removed use an explicit application descriptor. It could come in different flavors, the one I prefer if to drop a context descriptor file into <tomcatRoot>conf/Catalina/localhost directory. Name your context file the same as your application folder e.g. if you JABAWS resides in webappl/jabaws folder, then call the context file jabaws.xml. Below is an example of content this file might have.

+

<?xml version="1.0" encoding="UTF-8"?>
+ <Context antiResourceLocking="false" privileged="true" />

+

This should be sufficient to prevent Tomcat from removing your JABAWS from WEBAPPS. For more information about the Tomcat deployer read this documentation on the Apache-Tomcat web site.

+

Apache-Tomcat fails to deploy jabaws.war file

+
    +
  • Make sure Tomcat have sufficient access rights to read your war file.
  • +
  • Restart the Tomcat, sometimes it will not since that the new war file is added without restart
  • +
  • If Tomcat still refuses to unpack the war file, unpack it manually into web application folder (the war file is just a zip archive). Restart the Tomcat.
  • +
+
+ + + +
+ + +
+ + + + + + + + diff --git a/website/manual_qs_client.html b/website/manual_qs_client.html new file mode 100644 index 0000000..a8b6599 --- /dev/null +++ b/website/manual_qs_client.html @@ -0,0 +1,98 @@ + + + + + +Java Bioinformatics Analyses Web Services (JABAWS) manual - getting started + + + + + + +
+ +
+ + + +
+ +

Getting Started

+ +

Choose a JABAWS distribution

+ + + + + + + + + + + + + + + + + + +
I want to use JABAWS for...Quick Guide
Running Muptiple Sequence Alignments through Jalview on my own computerJABAWS Virtual Appliance (VA)
Running JABAWS for my group, lab, or organizationJABAWS Web Application aRchive (WAR)
Accessing a JABAWS server from my own codeJABAWS Java Client
+ + + + + +

The JABAWS command line client

+ +

+

This is a single java archive which contains the JABAWS command line client. +It requires Java version 1.6 to run, and allows anyone who wants to connect +to and to use JABAWS from their own software. +You can read more about how to use command line client in the CMD Client section of the manual. +You can also get command line help by changing to the directory where you downloaded the client jar, and typing: +

    +
  • java -jar min-jaba-client.jar
  • +

+

A JABAWS server's Web Services are WS-I compliant. This means that you can access them from any +language that has libraries or functions for consuming interoperable SOAP web services. +

+
+ +
+ + +
+ + + + + + + + diff --git a/website/manual_qs_va.html b/website/manual_qs_va.html new file mode 100644 index 0000000..e0c928e --- /dev/null +++ b/website/manual_qs_va.html @@ -0,0 +1,102 @@ + + + + + +Java Bioinformatics Analyses Web Services (JABAWS) manual - getting started + + + + + + +
+ +
+ + +
+ +

Getting Started

+ +

Choose a JABAWS distribution

+ + + + + + + + + + + + + + + + + + +
I want to use JABAWS for...Quick Guide
Running Muptiple Sequence Alignments through Jalview on my own computerJABAWS Virtual Appliance (VA)
Running JABAWS for my group, lab, or organizationJABAWS Web Application aRchive (WAR)
Accessing a JABAWS server from my own codeJABAWS Java Client
+ + +

Running JABAWS on your local machine

+
+

The Virtual Appliance (VA) package allows you to run a JABAWS server installed on TurnKey Linux as a virtual machine on your laptop or desktop computer. A complete guide to the JABAWS VA is given in the manual, but for the impatient, a brief instructions are given below: + +

If you work on Windows, Linux or Unix

+
    +
  1. download and install VMWare Player.
  2. +
  3. Unpack the JABAWS virtual appliance and open it with VMware Player.
  4. +
+

If you use a Mac, or prefer not to use VMWare, then :

+
    +
  1. download and install Virtual Box.
  2. +
  3. Unpack the JABAWS virtual appliance, import it into VirtualBox and then start the appliance.
  4. +
+
+

Testing

+

The easiest way to test that your JABAWS Virtual appliance is working is to use Jalview.

+
    +
  1. Launch the desktop version of Jalview
  2. +
  3. Open the Jalview desktop's preferences panel (from the Tools->Preferences menu option), select the Webservices panel and press the New Service URL button.
  4. +
  5. Enter the JABAWS URL for your new server. This is shown once the appliance is booted up.
  6. +
+
+
+ +
+ + +
+ + + + + + + + diff --git a/website/manual_qs_war.html b/website/manual_qs_war.html new file mode 100644 index 0000000..0887429 --- /dev/null +++ b/website/manual_qs_war.html @@ -0,0 +1,116 @@ + + + + + +Java Bioinformatics Analyses Web Services (JABAWS) manual - getting started + + + + + + +
+ + +
+ + +
+ +

Getting Started

+ +

Choose a JABAWS distribution

+ + + + + + + + + + + + + + + + + + +
I want to use JABAWS for...Quick Guide
Running Muptiple Sequence Alignments through Jalview on my own computerJABAWS Virtual Appliance (VA)
Running JABAWS for my group, lab, or organizationJABAWS Web Application aRchive (WAR)
Accessing a JABAWS server from my own codeJABAWS Java Client
+ + + +

Installing A JABAWS Server Web Application Archive (WAR) package

+ +

This is for anyone who wants to run JABAWS for their group, lab or organization, or wants to enable their local JABA server to use the cluster or perform very large tasks.

+ +
    +
  1. Download the JABAWS WAR with all binaries (45M)
  2. +
  3. Download and install Apache-Tomcat.
    + You will need at least version 5.5 of Tomcat (we would recommend version 6.0) and at least version 1.6 (i.e. JAVA 6) of Java.
  4. +
  5. Drop the JABAWS WAR file into tomcat/webapps directory.
  6. +
  7. (Re)start the Tomcat.
  8. +
  9. Once the tomcat has started, it should automatically unpack the WAR into the webapps directory (if it doesn't, then you'll need to do this manually, it's just a zip archive in the end).
  10. +
  11. You then need to complete the installation of the executable binaries:
  12. +
    • If you are on Linux
      cd to webapps/jabaws/binaries/src/ and execute ./setexecflag.sh script to ensure the JABAWS binaries can be executed.
    • +
    • If you are on a Mac (OSX intel mac only) or other unix-like architecture with gnu compilers available:
    • +
    • cd to webapps/jabaws/binaries/src/ and execute ./compilebin.sh script to compile all binaries JABAWS depends on.
    • +
    • cd to webapps/jabaws/binaries/src/ and execute ./setexecflag.sh script.
    • +
    +
+ +

Testing

+

You can test that your JABAWS server is working in two ways.

+
    +
  1. If you are working on the command line, then use the command line client shipped with the JABAWS war to test it by running: +java -jar <Path to tomcat WebApp directory>/jabaws/WEB-INF/lib/jaba-client.jar -h http://localhost:8080/jabaws +In this example we assumed that your JABAWS server URL is http://localhost:8080 and JABAWS context path is jabaws +
  2. + +
  3. Alternately, you can point Jalview at your new server: +
      +
    • Launch the desktop version of Jalview
    • +
    • Open the Jalview desktop's preferences panel (from the Tools->Preferences menu option), select the Webservices panel and press the New Service URL button.
    • +
    • Enter the URL for the tomcat server, including the context path for the JABAWS web app (e.g. http://localhost:8080/jabaws).
    • +
    +
+ + +
+ + + +
+ + + + +
+ + + diff --git a/website/print.css b/website/print.css new file mode 100644 index 0000000..4f6e7b8 --- /dev/null +++ b/website/print.css @@ -0,0 +1,188 @@ + +#banner { background:none !important; color:#000000 !important; text-align:center; } + +#panel { display:none !important } + +#content { margin:0.5em; border-bottom:solid 1px #6994af; } + +#page { margin: 0.5em; } + +#wrapper { background:none; } + +ul { + list-style-type: circle; +} + + +#panel a:link, a:visited { + text-decoration: none; + display:block; + line-height: 1em; + padding:10px; + color:#000000; + text-decoration:none; + } + +#panel a:hover { + background-color: transparent; + text-decoration: underline; + } + + +strong { + font-weight:bold; + color:#003366; +} + +pre { + font-family:Arial, Helvetica, sans-serif; +} + +p { + line-height: 1.4em; +} + +.hightlight { +font-style:italic; +font-family:"Courier New", Courier, monospace; +} + +.code { + font-size-adjust:0.4; + color:black; + background-color:#F5F5F5; + font-family:"Courier New",Courier,monospace; + font-style:normal; + margin:1em 0; + padding: 0.5em; + border: 1px dashed black; +} + + +.box { + font-size-adjust:0.5; + color:black; + background-color:#F5F5F5; + font-family:Arial, Helvetica, sans-serif; + font-style:normal; + margin:1em 0; + padding: 0.5em; + border: 1px solid black; + display:block; +} + +.u { text-decoration: underline; } +.headeru { text-shadow: black 0.05em 0.05em 0.01em ;} + +/* Table styles */ +table { + border-collapse: collapse; + border: 1px solid #666; + margin: 20px 0 20px 0; + width: 100%; +} +th, td { + margin: 2px 4px 2px 4px; + padding: 0 5px; + text-align: left; + vertical-align: top; + border: 1px solid #666; +} + +table caption { + font: 1.5em Georgia, "Times New Roman", Times, serif; + padding: 1em; + background-color: #9c9; +} + +.mainheader { + font: 1.5em Georgia, "Times New Roman", Times, serif; + background-color: #9c9; + text-align:center; + line-height:1em; +} + +tr { + background-color: #eee; +} + +tr:nth-child(odd) { + background-color: #ccc; +} + + +span.directory { +background: transparent url(images/dir.gif) no-repeat scroll left center; +color:#666666; +font-family:"Courier New",Courier,monospace; +font-style:normal; +padding:0 0 0 15px; +} + +.attention { +color:#993333; +} + +.source { + border:1px solid #858789; + display:block; + margin:26px 0; + overflow:visible; +} + +/* OPEN state styles */ +.source .body { + background:#F5F5F5 none repeat scroll right 0; + color:#434546; + padding:7px 15px; +/* white-space:pre-wrap; */ + word-wrap:break-word; +} + +.source .header { + background:#E9EAEC url(images/minus.png) no-repeat scroll 98% center; + color:#3B3D3F; + cursor:pointer; + font-weight:bold; + height:30px; + line-height:30px; + padding:0 0 0 15px; +} + +/* CLOSED state styles */ +.source .body.collapsed { + display:block !important; +} + +.source .header.collapsed { + background:#E9EAEC url(images/plus.png) no-repeat scroll 98% center; + padding:0 15px 0 15px; +} + +#copyright { text-align:right; + color:#999999; + font-family:Verdana, Arial, Helvetica, sans-serif; + font-size:smaller; + line-height:1em; + } + +.body .code { + margin:0; + padding:0; + border:0; + font-family:"Courier New",Courier,monospace; + font-style:normal; +} + +body { + font-family:Arial, Helvetica, sans-serif; + font-size: 9pt; + background-color: white; + line-height: 2em; +} + +h3 {border-bottom: 1px solid grey; margin-top: 2em; } + +#headtitle { margin:0; text-align:center; color:#003b62; font-weight:600;} + +h2 {margin:1.8em 0 0 0; color:#003b62; font-weight:600;} diff --git a/website/prototype-1.6.0.3.js b/website/prototype-1.6.0.3.js new file mode 100644 index 0000000..dfe8ab4 --- /dev/null +++ b/website/prototype-1.6.0.3.js @@ -0,0 +1,4320 @@ +/* Prototype JavaScript framework, version 1.6.0.3 + * (c) 2005-2008 Sam Stephenson + * + * Prototype is freely distributable under the terms of an MIT-style license. + * For details, see the Prototype web site: http://www.prototypejs.org/ + * + *--------------------------------------------------------------------------*/ + +var Prototype = { + Version: '1.6.0.3', + + Browser: { + IE: !!(window.attachEvent && + navigator.userAgent.indexOf('Opera') === -1), + Opera: navigator.userAgent.indexOf('Opera') > -1, + WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1, + Gecko: navigator.userAgent.indexOf('Gecko') > -1 && + navigator.userAgent.indexOf('KHTML') === -1, + MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/) + }, + + BrowserFeatures: { + XPath: !!document.evaluate, + SelectorsAPI: !!document.querySelector, + ElementExtensions: !!window.HTMLElement, + SpecificElementExtensions: + document.createElement('div')['__proto__'] && + document.createElement('div')['__proto__'] !== + document.createElement('form')['__proto__'] + }, + + ScriptFragment: ']*>([\\S\\s]*?)<\/script>', + JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, + + emptyFunction: function() { }, + K: function(x) { return x } +}; + +if (Prototype.Browser.MobileSafari) + Prototype.BrowserFeatures.SpecificElementExtensions = false; + + +/* Based on Alex Arnell's inheritance implementation. */ +var Class = { + create: function() { + var parent = null, properties = $A(arguments); + if (Object.isFunction(properties[0])) + parent = properties.shift(); + + function klass() { + this.initialize.apply(this, arguments); + } + + Object.extend(klass, Class.Methods); + klass.superclass = parent; + klass.subclasses = []; + + if (parent) { + var subclass = function() { }; + subclass.prototype = parent.prototype; + klass.prototype = new subclass; + parent.subclasses.push(klass); + } + + for (var i = 0; i < properties.length; i++) + klass.addMethods(properties[i]); + + if (!klass.prototype.initialize) + klass.prototype.initialize = Prototype.emptyFunction; + + klass.prototype.constructor = klass; + + return klass; + } +}; + +Class.Methods = { + addMethods: function(source) { + var ancestor = this.superclass && this.superclass.prototype; + var properties = Object.keys(source); + + if (!Object.keys({ toString: true }).length) + properties.push("toString", "valueOf"); + + for (var i = 0, length = properties.length; i < length; i++) { + var property = properties[i], value = source[property]; + if (ancestor && Object.isFunction(value) && + value.argumentNames().first() == "$super") { + var method = value; + value = (function(m) { + return function() { return ancestor[m].apply(this, arguments) }; + })(property).wrap(method); + + value.valueOf = method.valueOf.bind(method); + value.toString = method.toString.bind(method); + } + this.prototype[property] = value; + } + + return this; + } +}; + +var Abstract = { }; + +Object.extend = function(destination, source) { + for (var property in source) + destination[property] = source[property]; + return destination; +}; + +Object.extend(Object, { + inspect: function(object) { + try { + if (Object.isUndefined(object)) return 'undefined'; + if (object === null) return 'null'; + return object.inspect ? object.inspect() : String(object); + } catch (e) { + if (e instanceof RangeError) return '...'; + throw e; + } + }, + + toJSON: function(object) { + var type = typeof object; + switch (type) { + case 'undefined': + case 'function': + case 'unknown': return; + case 'boolean': return object.toString(); + } + + if (object === null) return 'null'; + if (object.toJSON) return object.toJSON(); + if (Object.isElement(object)) return; + + var results = []; + for (var property in object) { + var value = Object.toJSON(object[property]); + if (!Object.isUndefined(value)) + results.push(property.toJSON() + ': ' + value); + } + + return '{' + results.join(', ') + '}'; + }, + + toQueryString: function(object) { + return $H(object).toQueryString(); + }, + + toHTML: function(object) { + return object && object.toHTML ? object.toHTML() : String.interpret(object); + }, + + keys: function(object) { + var keys = []; + for (var property in object) + keys.push(property); + return keys; + }, + + values: function(object) { + var values = []; + for (var property in object) + values.push(object[property]); + return values; + }, + + clone: function(object) { + return Object.extend({ }, object); + }, + + isElement: function(object) { + return !!(object && object.nodeType == 1); + }, + + isArray: function(object) { + return object != null && typeof object == "object" && + 'splice' in object && 'join' in object; + }, + + isHash: function(object) { + return object instanceof Hash; + }, + + isFunction: function(object) { + return typeof object == "function"; + }, + + isString: function(object) { + return typeof object == "string"; + }, + + isNumber: function(object) { + return typeof object == "number"; + }, + + isUndefined: function(object) { + return typeof object == "undefined"; + } +}); + +Object.extend(Function.prototype, { + argumentNames: function() { + var names = this.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1] + .replace(/\s+/g, '').split(','); + return names.length == 1 && !names[0] ? [] : names; + }, + + bind: function() { + if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; + var __method = this, args = $A(arguments), object = args.shift(); + return function() { + return __method.apply(object, args.concat($A(arguments))); + } + }, + + bindAsEventListener: function() { + var __method = this, args = $A(arguments), object = args.shift(); + return function(event) { + return __method.apply(object, [event || window.event].concat(args)); + } + }, + + curry: function() { + if (!arguments.length) return this; + var __method = this, args = $A(arguments); + return function() { + return __method.apply(this, args.concat($A(arguments))); + } + }, + + delay: function() { + var __method = this, args = $A(arguments), timeout = args.shift() * 1000; + return window.setTimeout(function() { + return __method.apply(__method, args); + }, timeout); + }, + + defer: function() { + var args = [0.01].concat($A(arguments)); + return this.delay.apply(this, args); + }, + + wrap: function(wrapper) { + var __method = this; + return function() { + return wrapper.apply(this, [__method.bind(this)].concat($A(arguments))); + } + }, + + methodize: function() { + if (this._methodized) return this._methodized; + var __method = this; + return this._methodized = function() { + return __method.apply(null, [this].concat($A(arguments))); + }; + } +}); + +Date.prototype.toJSON = function() { + return '"' + this.getUTCFullYear() + '-' + + (this.getUTCMonth() + 1).toPaddedString(2) + '-' + + this.getUTCDate().toPaddedString(2) + 'T' + + this.getUTCHours().toPaddedString(2) + ':' + + this.getUTCMinutes().toPaddedString(2) + ':' + + this.getUTCSeconds().toPaddedString(2) + 'Z"'; +}; + +var Try = { + these: function() { + var returnValue; + + for (var i = 0, length = arguments.length; i < length; i++) { + var lambda = arguments[i]; + try { + returnValue = lambda(); + break; + } catch (e) { } + } + + return returnValue; + } +}; + +RegExp.prototype.match = RegExp.prototype.test; + +RegExp.escape = function(str) { + return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); +}; + +/*--------------------------------------------------------------------------*/ + +var PeriodicalExecuter = Class.create({ + initialize: function(callback, frequency) { + this.callback = callback; + this.frequency = frequency; + this.currentlyExecuting = false; + + this.registerCallback(); + }, + + registerCallback: function() { + this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + execute: function() { + this.callback(this); + }, + + stop: function() { + if (!this.timer) return; + clearInterval(this.timer); + this.timer = null; + }, + + onTimerEvent: function() { + if (!this.currentlyExecuting) { + try { + this.currentlyExecuting = true; + this.execute(); + } finally { + this.currentlyExecuting = false; + } + } + } +}); +Object.extend(String, { + interpret: function(value) { + return value == null ? '' : String(value); + }, + specialChar: { + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '\\': '\\\\' + } +}); + +Object.extend(String.prototype, { + gsub: function(pattern, replacement) { + var result = '', source = this, match; + replacement = arguments.callee.prepareReplacement(replacement); + + while (source.length > 0) { + if (match = source.match(pattern)) { + result += source.slice(0, match.index); + result += String.interpret(replacement(match)); + source = source.slice(match.index + match[0].length); + } else { + result += source, source = ''; + } + } + return result; + }, + + sub: function(pattern, replacement, count) { + replacement = this.gsub.prepareReplacement(replacement); + count = Object.isUndefined(count) ? 1 : count; + + return this.gsub(pattern, function(match) { + if (--count < 0) return match[0]; + return replacement(match); + }); + }, + + scan: function(pattern, iterator) { + this.gsub(pattern, iterator); + return String(this); + }, + + truncate: function(length, truncation) { + length = length || 30; + truncation = Object.isUndefined(truncation) ? '...' : truncation; + return this.length > length ? + this.slice(0, length - truncation.length) + truncation : String(this); + }, + + strip: function() { + return this.replace(/^\s+/, '').replace(/\s+$/, ''); + }, + + stripTags: function() { + return this.replace(/<\/?[^>]+>/gi, ''); + }, + + stripScripts: function() { + return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); + }, + + extractScripts: function() { + var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); + var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); + return (this.match(matchAll) || []).map(function(scriptTag) { + return (scriptTag.match(matchOne) || ['', ''])[1]; + }); + }, + + evalScripts: function() { + return this.extractScripts().map(function(script) { return eval(script) }); + }, + + escapeHTML: function() { + var self = arguments.callee; + self.text.data = this; + return self.div.innerHTML; + }, + + unescapeHTML: function() { + var div = new Element('div'); + div.innerHTML = this.stripTags(); + return div.childNodes[0] ? (div.childNodes.length > 1 ? + $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) : + div.childNodes[0].nodeValue) : ''; + }, + + toQueryParams: function(separator) { + var match = this.strip().match(/([^?#]*)(#.*)?$/); + if (!match) return { }; + + return match[1].split(separator || '&').inject({ }, function(hash, pair) { + if ((pair = pair.split('='))[0]) { + var key = decodeURIComponent(pair.shift()); + var value = pair.length > 1 ? pair.join('=') : pair[0]; + if (value != undefined) value = decodeURIComponent(value); + + if (key in hash) { + if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; + hash[key].push(value); + } + else hash[key] = value; + } + return hash; + }); + }, + + toArray: function() { + return this.split(''); + }, + + succ: function() { + return this.slice(0, this.length - 1) + + String.fromCharCode(this.charCodeAt(this.length - 1) + 1); + }, + + times: function(count) { + return count < 1 ? '' : new Array(count + 1).join(this); + }, + + camelize: function() { + var parts = this.split('-'), len = parts.length; + if (len == 1) return parts[0]; + + var camelized = this.charAt(0) == '-' + ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) + : parts[0]; + + for (var i = 1; i < len; i++) + camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); + + return camelized; + }, + + capitalize: function() { + return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); + }, + + underscore: function() { + return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); + }, + + dasherize: function() { + return this.gsub(/_/,'-'); + }, + + inspect: function(useDoubleQuotes) { + var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) { + var character = String.specialChar[match[0]]; + return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16); + }); + if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; + return "'" + escapedString.replace(/'/g, '\\\'') + "'"; + }, + + toJSON: function() { + return this.inspect(true); + }, + + unfilterJSON: function(filter) { + return this.sub(filter || Prototype.JSONFilter, '#{1}'); + }, + + isJSON: function() { + var str = this; + if (str.blank()) return false; + str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); + return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); + }, + + evalJSON: function(sanitize) { + var json = this.unfilterJSON(); + try { + if (!sanitize || json.isJSON()) return eval('(' + json + ')'); + } catch (e) { } + throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); + }, + + include: function(pattern) { + return this.indexOf(pattern) > -1; + }, + + startsWith: function(pattern) { + return this.indexOf(pattern) === 0; + }, + + endsWith: function(pattern) { + var d = this.length - pattern.length; + return d >= 0 && this.lastIndexOf(pattern) === d; + }, + + empty: function() { + return this == ''; + }, + + blank: function() { + return /^\s*$/.test(this); + }, + + interpolate: function(object, pattern) { + return new Template(this, pattern).evaluate(object); + } +}); + +if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, { + escapeHTML: function() { + return this.replace(/&/g,'&').replace(//g,'>'); + }, + unescapeHTML: function() { + return this.stripTags().replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); + } +}); + +String.prototype.gsub.prepareReplacement = function(replacement) { + if (Object.isFunction(replacement)) return replacement; + var template = new Template(replacement); + return function(match) { return template.evaluate(match) }; +}; + +String.prototype.parseQuery = String.prototype.toQueryParams; + +Object.extend(String.prototype.escapeHTML, { + div: document.createElement('div'), + text: document.createTextNode('') +}); + +String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text); + +var Template = Class.create({ + initialize: function(template, pattern) { + this.template = template.toString(); + this.pattern = pattern || Template.Pattern; + }, + + evaluate: function(object) { + if (Object.isFunction(object.toTemplateReplacements)) + object = object.toTemplateReplacements(); + + return this.template.gsub(this.pattern, function(match) { + if (object == null) return ''; + + var before = match[1] || ''; + if (before == '\\') return match[2]; + + var ctx = object, expr = match[3]; + var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; + match = pattern.exec(expr); + if (match == null) return before; + + while (match != null) { + var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1]; + ctx = ctx[comp]; + if (null == ctx || '' == match[3]) break; + expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); + match = pattern.exec(expr); + } + + return before + String.interpret(ctx); + }); + } +}); +Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; + +var $break = { }; + +var Enumerable = { + each: function(iterator, context) { + var index = 0; + try { + this._each(function(value) { + iterator.call(context, value, index++); + }); + } catch (e) { + if (e != $break) throw e; + } + return this; + }, + + eachSlice: function(number, iterator, context) { + var index = -number, slices = [], array = this.toArray(); + if (number < 1) return array; + while ((index += number) < array.length) + slices.push(array.slice(index, index+number)); + return slices.collect(iterator, context); + }, + + all: function(iterator, context) { + iterator = iterator || Prototype.K; + var result = true; + this.each(function(value, index) { + result = result && !!iterator.call(context, value, index); + if (!result) throw $break; + }); + return result; + }, + + any: function(iterator, context) { + iterator = iterator || Prototype.K; + var result = false; + this.each(function(value, index) { + if (result = !!iterator.call(context, value, index)) + throw $break; + }); + return result; + }, + + collect: function(iterator, context) { + iterator = iterator || Prototype.K; + var results = []; + this.each(function(value, index) { + results.push(iterator.call(context, value, index)); + }); + return results; + }, + + detect: function(iterator, context) { + var result; + this.each(function(value, index) { + if (iterator.call(context, value, index)) { + result = value; + throw $break; + } + }); + return result; + }, + + findAll: function(iterator, context) { + var results = []; + this.each(function(value, index) { + if (iterator.call(context, value, index)) + results.push(value); + }); + return results; + }, + + grep: function(filter, iterator, context) { + iterator = iterator || Prototype.K; + var results = []; + + if (Object.isString(filter)) + filter = new RegExp(filter); + + this.each(function(value, index) { + if (filter.match(value)) + results.push(iterator.call(context, value, index)); + }); + return results; + }, + + include: function(object) { + if (Object.isFunction(this.indexOf)) + if (this.indexOf(object) != -1) return true; + + var found = false; + this.each(function(value) { + if (value == object) { + found = true; + throw $break; + } + }); + return found; + }, + + inGroupsOf: function(number, fillWith) { + fillWith = Object.isUndefined(fillWith) ? null : fillWith; + return this.eachSlice(number, function(slice) { + while(slice.length < number) slice.push(fillWith); + return slice; + }); + }, + + inject: function(memo, iterator, context) { + this.each(function(value, index) { + memo = iterator.call(context, memo, value, index); + }); + return memo; + }, + + invoke: function(method) { + var args = $A(arguments).slice(1); + return this.map(function(value) { + return value[method].apply(value, args); + }); + }, + + max: function(iterator, context) { + iterator = iterator || Prototype.K; + var result; + this.each(function(value, index) { + value = iterator.call(context, value, index); + if (result == null || value >= result) + result = value; + }); + return result; + }, + + min: function(iterator, context) { + iterator = iterator || Prototype.K; + var result; + this.each(function(value, index) { + value = iterator.call(context, value, index); + if (result == null || value < result) + result = value; + }); + return result; + }, + + partition: function(iterator, context) { + iterator = iterator || Prototype.K; + var trues = [], falses = []; + this.each(function(value, index) { + (iterator.call(context, value, index) ? + trues : falses).push(value); + }); + return [trues, falses]; + }, + + pluck: function(property) { + var results = []; + this.each(function(value) { + results.push(value[property]); + }); + return results; + }, + + reject: function(iterator, context) { + var results = []; + this.each(function(value, index) { + if (!iterator.call(context, value, index)) + results.push(value); + }); + return results; + }, + + sortBy: function(iterator, context) { + return this.map(function(value, index) { + return { + value: value, + criteria: iterator.call(context, value, index) + }; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }).pluck('value'); + }, + + toArray: function() { + return this.map(); + }, + + zip: function() { + var iterator = Prototype.K, args = $A(arguments); + if (Object.isFunction(args.last())) + iterator = args.pop(); + + var collections = [this].concat(args).map($A); + return this.map(function(value, index) { + return iterator(collections.pluck(index)); + }); + }, + + size: function() { + return this.toArray().length; + }, + + inspect: function() { + return '#'; + } +}; + +Object.extend(Enumerable, { + map: Enumerable.collect, + find: Enumerable.detect, + select: Enumerable.findAll, + filter: Enumerable.findAll, + member: Enumerable.include, + entries: Enumerable.toArray, + every: Enumerable.all, + some: Enumerable.any +}); +function $A(iterable) { + if (!iterable) return []; + if (iterable.toArray) return iterable.toArray(); + var length = iterable.length || 0, results = new Array(length); + while (length--) results[length] = iterable[length]; + return results; +} + +if (Prototype.Browser.WebKit) { + $A = function(iterable) { + if (!iterable) return []; + // In Safari, only use the `toArray` method if it's not a NodeList. + // A NodeList is a function, has an function `item` property, and a numeric + // `length` property. Adapted from Google Doctype. + if (!(typeof iterable === 'function' && typeof iterable.length === + 'number' && typeof iterable.item === 'function') && iterable.toArray) + return iterable.toArray(); + var length = iterable.length || 0, results = new Array(length); + while (length--) results[length] = iterable[length]; + return results; + }; +} + +Array.from = $A; + +Object.extend(Array.prototype, Enumerable); + +if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse; + +Object.extend(Array.prototype, { + _each: function(iterator) { + for (var i = 0, length = this.length; i < length; i++) + iterator(this[i]); + }, + + clear: function() { + this.length = 0; + return this; + }, + + first: function() { + return this[0]; + }, + + last: function() { + return this[this.length - 1]; + }, + + compact: function() { + return this.select(function(value) { + return value != null; + }); + }, + + flatten: function() { + return this.inject([], function(array, value) { + return array.concat(Object.isArray(value) ? + value.flatten() : [value]); + }); + }, + + without: function() { + var values = $A(arguments); + return this.select(function(value) { + return !values.include(value); + }); + }, + + reverse: function(inline) { + return (inline !== false ? this : this.toArray())._reverse(); + }, + + reduce: function() { + return this.length > 1 ? this : this[0]; + }, + + uniq: function(sorted) { + return this.inject([], function(array, value, index) { + if (0 == index || (sorted ? array.last() != value : !array.include(value))) + array.push(value); + return array; + }); + }, + + intersect: function(array) { + return this.uniq().findAll(function(item) { + return array.detect(function(value) { return item === value }); + }); + }, + + clone: function() { + return [].concat(this); + }, + + size: function() { + return this.length; + }, + + inspect: function() { + return '[' + this.map(Object.inspect).join(', ') + ']'; + }, + + toJSON: function() { + var results = []; + this.each(function(object) { + var value = Object.toJSON(object); + if (!Object.isUndefined(value)) results.push(value); + }); + return '[' + results.join(', ') + ']'; + } +}); + +// use native browser JS 1.6 implementation if available +if (Object.isFunction(Array.prototype.forEach)) + Array.prototype._each = Array.prototype.forEach; + +if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) { + i || (i = 0); + var length = this.length; + if (i < 0) i = length + i; + for (; i < length; i++) + if (this[i] === item) return i; + return -1; +}; + +if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) { + i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; + var n = this.slice(0, i).reverse().indexOf(item); + return (n < 0) ? n : i - n - 1; +}; + +Array.prototype.toArray = Array.prototype.clone; + +function $w(string) { + if (!Object.isString(string)) return []; + string = string.strip(); + return string ? string.split(/\s+/) : []; +} + +if (Prototype.Browser.Opera){ + Array.prototype.concat = function() { + var array = []; + for (var i = 0, length = this.length; i < length; i++) array.push(this[i]); + for (var i = 0, length = arguments.length; i < length; i++) { + if (Object.isArray(arguments[i])) { + for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++) + array.push(arguments[i][j]); + } else { + array.push(arguments[i]); + } + } + return array; + }; +} +Object.extend(Number.prototype, { + toColorPart: function() { + return this.toPaddedString(2, 16); + }, + + succ: function() { + return this + 1; + }, + + times: function(iterator, context) { + $R(0, this, true).each(iterator, context); + return this; + }, + + toPaddedString: function(length, radix) { + var string = this.toString(radix || 10); + return '0'.times(length - string.length) + string; + }, + + toJSON: function() { + return isFinite(this) ? this.toString() : 'null'; + } +}); + +$w('abs round ceil floor').each(function(method){ + Number.prototype[method] = Math[method].methodize(); +}); +function $H(object) { + return new Hash(object); +}; + +var Hash = Class.create(Enumerable, (function() { + + function toQueryPair(key, value) { + if (Object.isUndefined(value)) return key; + return key + '=' + encodeURIComponent(String.interpret(value)); + } + + return { + initialize: function(object) { + this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); + }, + + _each: function(iterator) { + for (var key in this._object) { + var value = this._object[key], pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } + }, + + set: function(key, value) { + return this._object[key] = value; + }, + + get: function(key) { + // simulating poorly supported hasOwnProperty + if (this._object[key] !== Object.prototype[key]) + return this._object[key]; + }, + + unset: function(key) { + var value = this._object[key]; + delete this._object[key]; + return value; + }, + + toObject: function() { + return Object.clone(this._object); + }, + + keys: function() { + return this.pluck('key'); + }, + + values: function() { + return this.pluck('value'); + }, + + index: function(value) { + var match = this.detect(function(pair) { + return pair.value === value; + }); + return match && match.key; + }, + + merge: function(object) { + return this.clone().update(object); + }, + + update: function(object) { + return new Hash(object).inject(this, function(result, pair) { + result.set(pair.key, pair.value); + return result; + }); + }, + + toQueryString: function() { + return this.inject([], function(results, pair) { + var key = encodeURIComponent(pair.key), values = pair.value; + + if (values && typeof values == 'object') { + if (Object.isArray(values)) + return results.concat(values.map(toQueryPair.curry(key))); + } else results.push(toQueryPair(key, values)); + return results; + }).join('&'); + }, + + inspect: function() { + return '#'; + }, + + toJSON: function() { + return Object.toJSON(this.toObject()); + }, + + clone: function() { + return new Hash(this); + } + } +})()); + +Hash.prototype.toTemplateReplacements = Hash.prototype.toObject; +Hash.from = $H; +var ObjectRange = Class.create(Enumerable, { + initialize: function(start, end, exclusive) { + this.start = start; + this.end = end; + this.exclusive = exclusive; + }, + + _each: function(iterator) { + var value = this.start; + while (this.include(value)) { + iterator(value); + value = value.succ(); + } + }, + + include: function(value) { + if (value < this.start) + return false; + if (this.exclusive) + return value < this.end; + return value <= this.end; + } +}); + +var $R = function(start, end, exclusive) { + return new ObjectRange(start, end, exclusive); +}; + +var Ajax = { + getTransport: function() { + return Try.these( + function() {return new XMLHttpRequest()}, + function() {return new ActiveXObject('Msxml2.XMLHTTP')}, + function() {return new ActiveXObject('Microsoft.XMLHTTP')} + ) || false; + }, + + activeRequestCount: 0 +}; + +Ajax.Responders = { + responders: [], + + _each: function(iterator) { + this.responders._each(iterator); + }, + + register: function(responder) { + if (!this.include(responder)) + this.responders.push(responder); + }, + + unregister: function(responder) { + this.responders = this.responders.without(responder); + }, + + dispatch: function(callback, request, transport, json) { + this.each(function(responder) { + if (Object.isFunction(responder[callback])) { + try { + responder[callback].apply(responder, [request, transport, json]); + } catch (e) { } + } + }); + } +}; + +Object.extend(Ajax.Responders, Enumerable); + +Ajax.Responders.register({ + onCreate: function() { Ajax.activeRequestCount++ }, + onComplete: function() { Ajax.activeRequestCount-- } +}); + +Ajax.Base = Class.create({ + initialize: function(options) { + this.options = { + method: 'post', + asynchronous: true, + contentType: 'application/x-www-form-urlencoded', + encoding: 'UTF-8', + parameters: '', + evalJSON: true, + evalJS: true + }; + Object.extend(this.options, options || { }); + + this.options.method = this.options.method.toLowerCase(); + + if (Object.isString(this.options.parameters)) + this.options.parameters = this.options.parameters.toQueryParams(); + else if (Object.isHash(this.options.parameters)) + this.options.parameters = this.options.parameters.toObject(); + } +}); + +Ajax.Request = Class.create(Ajax.Base, { + _complete: false, + + initialize: function($super, url, options) { + $super(options); + this.transport = Ajax.getTransport(); + this.request(url); + }, + + request: function(url) { + this.url = url; + this.method = this.options.method; + var params = Object.clone(this.options.parameters); + + if (!['get', 'post'].include(this.method)) { + // simulate other verbs over post + params['_method'] = this.method; + this.method = 'post'; + } + + this.parameters = params; + + if (params = Object.toQueryString(params)) { + // when GET, append parameters to URL + if (this.method == 'get') + this.url += (this.url.include('?') ? '&' : '?') + params; + else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) + params += '&_='; + } + + try { + var response = new Ajax.Response(this); + if (this.options.onCreate) this.options.onCreate(response); + Ajax.Responders.dispatch('onCreate', this, response); + + this.transport.open(this.method.toUpperCase(), this.url, + this.options.asynchronous); + + if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); + + this.transport.onreadystatechange = this.onStateChange.bind(this); + this.setRequestHeaders(); + + this.body = this.method == 'post' ? (this.options.postBody || params) : null; + this.transport.send(this.body); + + /* Force Firefox to handle ready state 4 for synchronous requests */ + if (!this.options.asynchronous && this.transport.overrideMimeType) + this.onStateChange(); + + } + catch (e) { + this.dispatchException(e); + } + }, + + onStateChange: function() { + var readyState = this.transport.readyState; + if (readyState > 1 && !((readyState == 4) && this._complete)) + this.respondToReadyState(this.transport.readyState); + }, + + setRequestHeaders: function() { + var headers = { + 'X-Requested-With': 'XMLHttpRequest', + 'X-Prototype-Version': Prototype.Version, + 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' + }; + + if (this.method == 'post') { + headers['Content-type'] = this.options.contentType + + (this.options.encoding ? '; charset=' + this.options.encoding : ''); + + /* Force "Connection: close" for older Mozilla browsers to work + * around a bug where XMLHttpRequest sends an incorrect + * Content-length header. See Mozilla Bugzilla #246651. + */ + if (this.transport.overrideMimeType && + (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) + headers['Connection'] = 'close'; + } + + // user-defined headers + if (typeof this.options.requestHeaders == 'object') { + var extras = this.options.requestHeaders; + + if (Object.isFunction(extras.push)) + for (var i = 0, length = extras.length; i < length; i += 2) + headers[extras[i]] = extras[i+1]; + else + $H(extras).each(function(pair) { headers[pair.key] = pair.value }); + } + + for (var name in headers) + this.transport.setRequestHeader(name, headers[name]); + }, + + success: function() { + var status = this.getStatus(); + return !status || (status >= 200 && status < 300); + }, + + getStatus: function() { + try { + return this.transport.status || 0; + } catch (e) { return 0 } + }, + + respondToReadyState: function(readyState) { + var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this); + + if (state == 'Complete') { + try { + this._complete = true; + (this.options['on' + response.status] + || this.options['on' + (this.success() ? 'Success' : 'Failure')] + || Prototype.emptyFunction)(response, response.headerJSON); + } catch (e) { + this.dispatchException(e); + } + + var contentType = response.getHeader('Content-type'); + if (this.options.evalJS == 'force' + || (this.options.evalJS && this.isSameOrigin() && contentType + && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))) + this.evalResponse(); + } + + try { + (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON); + Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON); + } catch (e) { + this.dispatchException(e); + } + + if (state == 'Complete') { + // avoid memory leak in MSIE: clean up + this.transport.onreadystatechange = Prototype.emptyFunction; + } + }, + + isSameOrigin: function() { + var m = this.url.match(/^\s*https?:\/\/[^\/]*/); + return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ + protocol: location.protocol, + domain: document.domain, + port: location.port ? ':' + location.port : '' + })); + }, + + getHeader: function(name) { + try { + return this.transport.getResponseHeader(name) || null; + } catch (e) { return null } + }, + + evalResponse: function() { + try { + return eval((this.transport.responseText || '').unfilterJSON()); + } catch (e) { + this.dispatchException(e); + } + }, + + dispatchException: function(exception) { + (this.options.onException || Prototype.emptyFunction)(this, exception); + Ajax.Responders.dispatch('onException', this, exception); + } +}); + +Ajax.Request.Events = + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; + +Ajax.Response = Class.create({ + initialize: function(request){ + this.request = request; + var transport = this.transport = request.transport, + readyState = this.readyState = transport.readyState; + + if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { + this.status = this.getStatus(); + this.statusText = this.getStatusText(); + this.responseText = String.interpret(transport.responseText); + this.headerJSON = this._getHeaderJSON(); + } + + if(readyState == 4) { + var xml = transport.responseXML; + this.responseXML = Object.isUndefined(xml) ? null : xml; + this.responseJSON = this._getResponseJSON(); + } + }, + + status: 0, + statusText: '', + + getStatus: Ajax.Request.prototype.getStatus, + + getStatusText: function() { + try { + return this.transport.statusText || ''; + } catch (e) { return '' } + }, + + getHeader: Ajax.Request.prototype.getHeader, + + getAllHeaders: function() { + try { + return this.getAllResponseHeaders(); + } catch (e) { return null } + }, + + getResponseHeader: function(name) { + return this.transport.getResponseHeader(name); + }, + + getAllResponseHeaders: function() { + return this.transport.getAllResponseHeaders(); + }, + + _getHeaderJSON: function() { + var json = this.getHeader('X-JSON'); + if (!json) return null; + json = decodeURIComponent(escape(json)); + try { + return json.evalJSON(this.request.options.sanitizeJSON || + !this.request.isSameOrigin()); + } catch (e) { + this.request.dispatchException(e); + } + }, + + _getResponseJSON: function() { + var options = this.request.options; + if (!options.evalJSON || (options.evalJSON != 'force' && + !(this.getHeader('Content-type') || '').include('application/json')) || + this.responseText.blank()) + return null; + try { + return this.responseText.evalJSON(options.sanitizeJSON || + !this.request.isSameOrigin()); + } catch (e) { + this.request.dispatchException(e); + } + } +}); + +Ajax.Updater = Class.create(Ajax.Request, { + initialize: function($super, container, url, options) { + this.container = { + success: (container.success || container), + failure: (container.failure || (container.success ? null : container)) + }; + + options = Object.clone(options); + var onComplete = options.onComplete; + options.onComplete = (function(response, json) { + this.updateContent(response.responseText); + if (Object.isFunction(onComplete)) onComplete(response, json); + }).bind(this); + + $super(url, options); + }, + + updateContent: function(responseText) { + var receiver = this.container[this.success() ? 'success' : 'failure'], + options = this.options; + + if (!options.evalScripts) responseText = responseText.stripScripts(); + + if (receiver = $(receiver)) { + if (options.insertion) { + if (Object.isString(options.insertion)) { + var insertion = { }; insertion[options.insertion] = responseText; + receiver.insert(insertion); + } + else options.insertion(receiver, responseText); + } + else receiver.update(responseText); + } + } +}); + +Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { + initialize: function($super, container, url, options) { + $super(options); + this.onComplete = this.options.onComplete; + + this.frequency = (this.options.frequency || 2); + this.decay = (this.options.decay || 1); + + this.updater = { }; + this.container = container; + this.url = url; + + this.start(); + }, + + start: function() { + this.options.onComplete = this.updateComplete.bind(this); + this.onTimerEvent(); + }, + + stop: function() { + this.updater.options.onComplete = undefined; + clearTimeout(this.timer); + (this.onComplete || Prototype.emptyFunction).apply(this, arguments); + }, + + updateComplete: function(response) { + if (this.options.decay) { + this.decay = (response.responseText == this.lastText ? + this.decay * this.options.decay : 1); + + this.lastText = response.responseText; + } + this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); + }, + + onTimerEvent: function() { + this.updater = new Ajax.Updater(this.container, this.url, this.options); + } +}); +function $(element) { + if (arguments.length > 1) { + for (var i = 0, elements = [], length = arguments.length; i < length; i++) + elements.push($(arguments[i])); + return elements; + } + if (Object.isString(element)) + element = document.getElementById(element); + return Element.extend(element); +} + +if (Prototype.BrowserFeatures.XPath) { + document._getElementsByXPath = function(expression, parentElement) { + var results = []; + var query = document.evaluate(expression, $(parentElement) || document, + null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + for (var i = 0, length = query.snapshotLength; i < length; i++) + results.push(Element.extend(query.snapshotItem(i))); + return results; + }; +} + +/*--------------------------------------------------------------------------*/ + +if (!window.Node) var Node = { }; + +if (!Node.ELEMENT_NODE) { + // DOM level 2 ECMAScript Language Binding + Object.extend(Node, { + ELEMENT_NODE: 1, + ATTRIBUTE_NODE: 2, + TEXT_NODE: 3, + CDATA_SECTION_NODE: 4, + ENTITY_REFERENCE_NODE: 5, + ENTITY_NODE: 6, + PROCESSING_INSTRUCTION_NODE: 7, + COMMENT_NODE: 8, + DOCUMENT_NODE: 9, + DOCUMENT_TYPE_NODE: 10, + DOCUMENT_FRAGMENT_NODE: 11, + NOTATION_NODE: 12 + }); +} + +(function() { + var element = this.Element; + this.Element = function(tagName, attributes) { + attributes = attributes || { }; + tagName = tagName.toLowerCase(); + var cache = Element.cache; + if (Prototype.Browser.IE && attributes.name) { + tagName = '<' + tagName + ' name="' + attributes.name + '">'; + delete attributes.name; + return Element.writeAttribute(document.createElement(tagName), attributes); + } + if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); + return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); + }; + Object.extend(this.Element, element || { }); + if (element) this.Element.prototype = element.prototype; +}).call(window); + +Element.cache = { }; + +Element.Methods = { + visible: function(element) { + return $(element).style.display != 'none'; + }, + + toggle: function(element) { + element = $(element); + Element[Element.visible(element) ? 'hide' : 'show'](element); + return element; + }, + + hide: function(element) { + element = $(element); + element.style.display = 'none'; + return element; + }, + + show: function(element) { + element = $(element); + element.style.display = ''; + return element; + }, + + remove: function(element) { + element = $(element); + element.parentNode.removeChild(element); + return element; + }, + + update: function(element, content) { + element = $(element); + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) return element.update().insert(content); + content = Object.toHTML(content); + element.innerHTML = content.stripScripts(); + content.evalScripts.bind(content).defer(); + return element; + }, + + replace: function(element, content) { + element = $(element); + if (content && content.toElement) content = content.toElement(); + else if (!Object.isElement(content)) { + content = Object.toHTML(content); + var range = element.ownerDocument.createRange(); + range.selectNode(element); + content.evalScripts.bind(content).defer(); + content = range.createContextualFragment(content.stripScripts()); + } + element.parentNode.replaceChild(content, element); + return element; + }, + + insert: function(element, insertions) { + element = $(element); + + if (Object.isString(insertions) || Object.isNumber(insertions) || + Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) + insertions = {bottom:insertions}; + + var content, insert, tagName, childNodes; + + for (var position in insertions) { + content = insertions[position]; + position = position.toLowerCase(); + insert = Element._insertionTranslations[position]; + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) { + insert(element, content); + continue; + } + + content = Object.toHTML(content); + + tagName = ((position == 'before' || position == 'after') + ? element.parentNode : element).tagName.toUpperCase(); + + childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); + + if (position == 'top' || position == 'after') childNodes.reverse(); + childNodes.each(insert.curry(element)); + + content.evalScripts.bind(content).defer(); + } + + return element; + }, + + wrap: function(element, wrapper, attributes) { + element = $(element); + if (Object.isElement(wrapper)) + $(wrapper).writeAttribute(attributes || { }); + else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes); + else wrapper = new Element('div', wrapper); + if (element.parentNode) + element.parentNode.replaceChild(wrapper, element); + wrapper.appendChild(element); + return wrapper; + }, + + inspect: function(element) { + element = $(element); + var result = '<' + element.tagName.toLowerCase(); + $H({'id': 'id', 'className': 'class'}).each(function(pair) { + var property = pair.first(), attribute = pair.last(); + var value = (element[property] || '').toString(); + if (value) result += ' ' + attribute + '=' + value.inspect(true); + }); + return result + '>'; + }, + + recursivelyCollect: function(element, property) { + element = $(element); + var elements = []; + while (element = element[property]) + if (element.nodeType == 1) + elements.push(Element.extend(element)); + return elements; + }, + + ancestors: function(element) { + return $(element).recursivelyCollect('parentNode'); + }, + + descendants: function(element) { + return $(element).select("*"); + }, + + firstDescendant: function(element) { + element = $(element).firstChild; + while (element && element.nodeType != 1) element = element.nextSibling; + return $(element); + }, + + immediateDescendants: function(element) { + if (!(element = $(element).firstChild)) return []; + while (element && element.nodeType != 1) element = element.nextSibling; + if (element) return [element].concat($(element).nextSiblings()); + return []; + }, + + previousSiblings: function(element) { + return $(element).recursivelyCollect('previousSibling'); + }, + + nextSiblings: function(element) { + return $(element).recursivelyCollect('nextSibling'); + }, + + siblings: function(element) { + element = $(element); + return element.previousSiblings().reverse().concat(element.nextSiblings()); + }, + + match: function(element, selector) { + if (Object.isString(selector)) + selector = new Selector(selector); + return selector.match($(element)); + }, + + up: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(element.parentNode); + var ancestors = element.ancestors(); + return Object.isNumber(expression) ? ancestors[expression] : + Selector.findElement(ancestors, expression, index); + }, + + down: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return element.firstDescendant(); + return Object.isNumber(expression) ? element.descendants()[expression] : + Element.select(element, expression)[index || 0]; + }, + + previous: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); + var previousSiblings = element.previousSiblings(); + return Object.isNumber(expression) ? previousSiblings[expression] : + Selector.findElement(previousSiblings, expression, index); + }, + + next: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); + var nextSiblings = element.nextSiblings(); + return Object.isNumber(expression) ? nextSiblings[expression] : + Selector.findElement(nextSiblings, expression, index); + }, + + select: function() { + var args = $A(arguments), element = $(args.shift()); + return Selector.findChildElements(element, args); + }, + + adjacent: function() { + var args = $A(arguments), element = $(args.shift()); + return Selector.findChildElements(element.parentNode, args).without(element); + }, + + identify: function(element) { + element = $(element); + var id = element.readAttribute('id'), self = arguments.callee; + if (id) return id; + do { id = 'anonymous_element_' + self.counter++ } while ($(id)); + element.writeAttribute('id', id); + return id; + }, + + readAttribute: function(element, name) { + element = $(element); + if (Prototype.Browser.IE) { + var t = Element._attributeTranslations.read; + if (t.values[name]) return t.values[name](element, name); + if (t.names[name]) name = t.names[name]; + if (name.include(':')) { + return (!element.attributes || !element.attributes[name]) ? null : + element.attributes[name].value; + } + } + return element.getAttribute(name); + }, + + writeAttribute: function(element, name, value) { + element = $(element); + var attributes = { }, t = Element._attributeTranslations.write; + + if (typeof name == 'object') attributes = name; + else attributes[name] = Object.isUndefined(value) ? true : value; + + for (var attr in attributes) { + name = t.names[attr] || attr; + value = attributes[attr]; + if (t.values[attr]) name = t.values[attr](element, value); + if (value === false || value === null) + element.removeAttribute(name); + else if (value === true) + element.setAttribute(name, name); + else element.setAttribute(name, value); + } + return element; + }, + + getHeight: function(element) { + return $(element).getDimensions().height; + }, + + getWidth: function(element) { + return $(element).getDimensions().width; + }, + + classNames: function(element) { + return new Element.ClassNames(element); + }, + + hasClassName: function(element, className) { + if (!(element = $(element))) return; + var elementClassName = element.className; + return (elementClassName.length > 0 && (elementClassName == className || + new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName))); + }, + + addClassName: function(element, className) { + if (!(element = $(element))) return; + if (!element.hasClassName(className)) + element.className += (element.className ? ' ' : '') + className; + return element; + }, + + removeClassName: function(element, className) { + if (!(element = $(element))) return; + element.className = element.className.replace( + new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip(); + return element; + }, + + toggleClassName: function(element, className) { + if (!(element = $(element))) return; + return element[element.hasClassName(className) ? + 'removeClassName' : 'addClassName'](className); + }, + + // removes whitespace-only text node children + cleanWhitespace: function(element) { + element = $(element); + var node = element.firstChild; + while (node) { + var nextNode = node.nextSibling; + if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) + element.removeChild(node); + node = nextNode; + } + return element; + }, + + empty: function(element) { + return $(element).innerHTML.blank(); + }, + + descendantOf: function(element, ancestor) { + element = $(element), ancestor = $(ancestor); + + if (element.compareDocumentPosition) + return (element.compareDocumentPosition(ancestor) & 8) === 8; + + if (ancestor.contains) + return ancestor.contains(element) && ancestor !== element; + + while (element = element.parentNode) + if (element == ancestor) return true; + + return false; + }, + + scrollTo: function(element) { + element = $(element); + var pos = element.cumulativeOffset(); + window.scrollTo(pos[0], pos[1]); + return element; + }, + + getStyle: function(element, style) { + element = $(element); + style = style == 'float' ? 'cssFloat' : style.camelize(); + var value = element.style[style]; + if (!value || value == 'auto') { + var css = document.defaultView.getComputedStyle(element, null); + value = css ? css[style] : null; + } + if (style == 'opacity') return value ? parseFloat(value) : 1.0; + return value == 'auto' ? null : value; + }, + + getOpacity: function(element) { + return $(element).getStyle('opacity'); + }, + + setStyle: function(element, styles) { + element = $(element); + var elementStyle = element.style, match; + if (Object.isString(styles)) { + element.style.cssText += ';' + styles; + return styles.include('opacity') ? + element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element; + } + for (var property in styles) + if (property == 'opacity') element.setOpacity(styles[property]); + else + elementStyle[(property == 'float' || property == 'cssFloat') ? + (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') : + property] = styles[property]; + + return element; + }, + + setOpacity: function(element, value) { + element = $(element); + element.style.opacity = (value == 1 || value === '') ? '' : + (value < 0.00001) ? 0 : value; + return element; + }, + + getDimensions: function(element) { + element = $(element); + var display = element.getStyle('display'); + if (display != 'none' && display != null) // Safari bug + return {width: element.offsetWidth, height: element.offsetHeight}; + + // All *Width and *Height properties give 0 on elements with display none, + // so enable the element temporarily + var els = element.style; + var originalVisibility = els.visibility; + var originalPosition = els.position; + var originalDisplay = els.display; + els.visibility = 'hidden'; + els.position = 'absolute'; + els.display = 'block'; + var originalWidth = element.clientWidth; + var originalHeight = element.clientHeight; + els.display = originalDisplay; + els.position = originalPosition; + els.visibility = originalVisibility; + return {width: originalWidth, height: originalHeight}; + }, + + makePositioned: function(element) { + element = $(element); + var pos = Element.getStyle(element, 'position'); + if (pos == 'static' || !pos) { + element._madePositioned = true; + element.style.position = 'relative'; + // Opera returns the offset relative to the positioning context, when an + // element is position relative but top and left have not been defined + if (Prototype.Browser.Opera) { + element.style.top = 0; + element.style.left = 0; + } + } + return element; + }, + + undoPositioned: function(element) { + element = $(element); + if (element._madePositioned) { + element._madePositioned = undefined; + element.style.position = + element.style.top = + element.style.left = + element.style.bottom = + element.style.right = ''; + } + return element; + }, + + makeClipping: function(element) { + element = $(element); + if (element._overflow) return element; + element._overflow = Element.getStyle(element, 'overflow') || 'auto'; + if (element._overflow !== 'hidden') + element.style.overflow = 'hidden'; + return element; + }, + + undoClipping: function(element) { + element = $(element); + if (!element._overflow) return element; + element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; + element._overflow = null; + return element; + }, + + cumulativeOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + return Element._returnOffset(valueL, valueT); + }, + + positionedOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + if (element) { + if (element.tagName.toUpperCase() == 'BODY') break; + var p = Element.getStyle(element, 'position'); + if (p !== 'static') break; + } + } while (element); + return Element._returnOffset(valueL, valueT); + }, + + absolutize: function(element) { + element = $(element); + if (element.getStyle('position') == 'absolute') return element; + // Position.prepare(); // To be done manually by Scripty when it needs it. + + var offsets = element.positionedOffset(); + var top = offsets[1]; + var left = offsets[0]; + var width = element.clientWidth; + var height = element.clientHeight; + + element._originalLeft = left - parseFloat(element.style.left || 0); + element._originalTop = top - parseFloat(element.style.top || 0); + element._originalWidth = element.style.width; + element._originalHeight = element.style.height; + + element.style.position = 'absolute'; + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.width = width + 'px'; + element.style.height = height + 'px'; + return element; + }, + + relativize: function(element) { + element = $(element); + if (element.getStyle('position') == 'relative') return element; + // Position.prepare(); // To be done manually by Scripty when it needs it. + + element.style.position = 'relative'; + var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); + var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); + + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.height = element._originalHeight; + element.style.width = element._originalWidth; + return element; + }, + + cumulativeScrollOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.scrollTop || 0; + valueL += element.scrollLeft || 0; + element = element.parentNode; + } while (element); + return Element._returnOffset(valueL, valueT); + }, + + getOffsetParent: function(element) { + if (element.offsetParent) return $(element.offsetParent); + if (element == document.body) return $(element); + + while ((element = element.parentNode) && element != document.body) + if (Element.getStyle(element, 'position') != 'static') + return $(element); + + return $(document.body); + }, + + viewportOffset: function(forElement) { + var valueT = 0, valueL = 0; + + var element = forElement; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + + // Safari fix + if (element.offsetParent == document.body && + Element.getStyle(element, 'position') == 'absolute') break; + + } while (element = element.offsetParent); + + element = forElement; + do { + if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } + } while (element = element.parentNode); + + return Element._returnOffset(valueL, valueT); + }, + + clonePosition: function(element, source) { + var options = Object.extend({ + setLeft: true, + setTop: true, + setWidth: true, + setHeight: true, + offsetTop: 0, + offsetLeft: 0 + }, arguments[2] || { }); + + // find page position of source + source = $(source); + var p = source.viewportOffset(); + + // find coordinate system to use + element = $(element); + var delta = [0, 0]; + var parent = null; + // delta [0,0] will do fine with position: fixed elements, + // position:absolute needs offsetParent deltas + if (Element.getStyle(element, 'position') == 'absolute') { + parent = element.getOffsetParent(); + delta = parent.viewportOffset(); + } + + // correct by body offsets (fixes Safari) + if (parent == document.body) { + delta[0] -= document.body.offsetLeft; + delta[1] -= document.body.offsetTop; + } + + // set position + if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; + if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; + if (options.setWidth) element.style.width = source.offsetWidth + 'px'; + if (options.setHeight) element.style.height = source.offsetHeight + 'px'; + return element; + } +}; + +Element.Methods.identify.counter = 1; + +Object.extend(Element.Methods, { + getElementsBySelector: Element.Methods.select, + childElements: Element.Methods.immediateDescendants +}); + +Element._attributeTranslations = { + write: { + names: { + className: 'class', + htmlFor: 'for' + }, + values: { } + } +}; + +if (Prototype.Browser.Opera) { + Element.Methods.getStyle = Element.Methods.getStyle.wrap( + function(proceed, element, style) { + switch (style) { + case 'left': case 'top': case 'right': case 'bottom': + if (proceed(element, 'position') === 'static') return null; + case 'height': case 'width': + // returns '0px' for hidden elements; we want it to return null + if (!Element.visible(element)) return null; + + // returns the border-box dimensions rather than the content-box + // dimensions, so we subtract padding and borders from the value + var dim = parseInt(proceed(element, style), 10); + + if (dim !== element['offset' + style.capitalize()]) + return dim + 'px'; + + var properties; + if (style === 'height') { + properties = ['border-top-width', 'padding-top', + 'padding-bottom', 'border-bottom-width']; + } + else { + properties = ['border-left-width', 'padding-left', + 'padding-right', 'border-right-width']; + } + return properties.inject(dim, function(memo, property) { + var val = proceed(element, property); + return val === null ? memo : memo - parseInt(val, 10); + }) + 'px'; + default: return proceed(element, style); + } + } + ); + + Element.Methods.readAttribute = Element.Methods.readAttribute.wrap( + function(proceed, element, attribute) { + if (attribute === 'title') return element.title; + return proceed(element, attribute); + } + ); +} + +else if (Prototype.Browser.IE) { + // IE doesn't report offsets correctly for static elements, so we change them + // to "relative" to get the values, then change them back. + Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( + function(proceed, element) { + element = $(element); + // IE throws an error if element is not in document + try { element.offsetParent } + catch(e) { return $(document.body) } + var position = element.getStyle('position'); + if (position !== 'static') return proceed(element); + element.setStyle({ position: 'relative' }); + var value = proceed(element); + element.setStyle({ position: position }); + return value; + } + ); + + $w('positionedOffset viewportOffset').each(function(method) { + Element.Methods[method] = Element.Methods[method].wrap( + function(proceed, element) { + element = $(element); + try { element.offsetParent } + catch(e) { return Element._returnOffset(0,0) } + var position = element.getStyle('position'); + if (position !== 'static') return proceed(element); + // Trigger hasLayout on the offset parent so that IE6 reports + // accurate offsetTop and offsetLeft values for position: fixed. + var offsetParent = element.getOffsetParent(); + if (offsetParent && offsetParent.getStyle('position') === 'fixed') + offsetParent.setStyle({ zoom: 1 }); + element.setStyle({ position: 'relative' }); + var value = proceed(element); + element.setStyle({ position: position }); + return value; + } + ); + }); + + Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap( + function(proceed, element) { + try { element.offsetParent } + catch(e) { return Element._returnOffset(0,0) } + return proceed(element); + } + ); + + Element.Methods.getStyle = function(element, style) { + element = $(element); + style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); + var value = element.style[style]; + if (!value && element.currentStyle) value = element.currentStyle[style]; + + if (style == 'opacity') { + if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) + if (value[1]) return parseFloat(value[1]) / 100; + return 1.0; + } + + if (value == 'auto') { + if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) + return element['offset' + style.capitalize()] + 'px'; + return null; + } + return value; + }; + + Element.Methods.setOpacity = function(element, value) { + function stripAlpha(filter){ + return filter.replace(/alpha\([^\)]*\)/gi,''); + } + element = $(element); + var currentStyle = element.currentStyle; + if ((currentStyle && !currentStyle.hasLayout) || + (!currentStyle && element.style.zoom == 'normal')) + element.style.zoom = 1; + + var filter = element.getStyle('filter'), style = element.style; + if (value == 1 || value === '') { + (filter = stripAlpha(filter)) ? + style.filter = filter : style.removeAttribute('filter'); + return element; + } else if (value < 0.00001) value = 0; + style.filter = stripAlpha(filter) + + 'alpha(opacity=' + (value * 100) + ')'; + return element; + }; + + Element._attributeTranslations = { + read: { + names: { + 'class': 'className', + 'for': 'htmlFor' + }, + values: { + _getAttr: function(element, attribute) { + return element.getAttribute(attribute, 2); + }, + _getAttrNode: function(element, attribute) { + var node = element.getAttributeNode(attribute); + return node ? node.value : ""; + }, + _getEv: function(element, attribute) { + attribute = element.getAttribute(attribute); + return attribute ? attribute.toString().slice(23, -2) : null; + }, + _flag: function(element, attribute) { + return $(element).hasAttribute(attribute) ? attribute : null; + }, + style: function(element) { + return element.style.cssText.toLowerCase(); + }, + title: function(element) { + return element.title; + } + } + } + }; + + Element._attributeTranslations.write = { + names: Object.extend({ + cellpadding: 'cellPadding', + cellspacing: 'cellSpacing' + }, Element._attributeTranslations.read.names), + values: { + checked: function(element, value) { + element.checked = !!value; + }, + + style: function(element, value) { + element.style.cssText = value ? value : ''; + } + } + }; + + Element._attributeTranslations.has = {}; + + $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + + 'encType maxLength readOnly longDesc frameBorder').each(function(attr) { + Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; + Element._attributeTranslations.has[attr.toLowerCase()] = attr; + }); + + (function(v) { + Object.extend(v, { + href: v._getAttr, + src: v._getAttr, + type: v._getAttr, + action: v._getAttrNode, + disabled: v._flag, + checked: v._flag, + readonly: v._flag, + multiple: v._flag, + onload: v._getEv, + onunload: v._getEv, + onclick: v._getEv, + ondblclick: v._getEv, + onmousedown: v._getEv, + onmouseup: v._getEv, + onmouseover: v._getEv, + onmousemove: v._getEv, + onmouseout: v._getEv, + onfocus: v._getEv, + onblur: v._getEv, + onkeypress: v._getEv, + onkeydown: v._getEv, + onkeyup: v._getEv, + onsubmit: v._getEv, + onreset: v._getEv, + onselect: v._getEv, + onchange: v._getEv + }); + })(Element._attributeTranslations.read.values); +} + +else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { + Element.Methods.setOpacity = function(element, value) { + element = $(element); + element.style.opacity = (value == 1) ? 0.999999 : + (value === '') ? '' : (value < 0.00001) ? 0 : value; + return element; + }; +} + +else if (Prototype.Browser.WebKit) { + Element.Methods.setOpacity = function(element, value) { + element = $(element); + element.style.opacity = (value == 1 || value === '') ? '' : + (value < 0.00001) ? 0 : value; + + if (value == 1) + if(element.tagName.toUpperCase() == 'IMG' && element.width) { + element.width++; element.width--; + } else try { + var n = document.createTextNode(' '); + element.appendChild(n); + element.removeChild(n); + } catch (e) { } + + return element; + }; + + // Safari returns margins on body which is incorrect if the child is absolutely + // positioned. For performance reasons, redefine Element#cumulativeOffset for + // KHTML/WebKit only. + Element.Methods.cumulativeOffset = function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == document.body) + if (Element.getStyle(element, 'position') == 'absolute') break; + + element = element.offsetParent; + } while (element); + + return Element._returnOffset(valueL, valueT); + }; +} + +if (Prototype.Browser.IE || Prototype.Browser.Opera) { + // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements + Element.Methods.update = function(element, content) { + element = $(element); + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) return element.update().insert(content); + + content = Object.toHTML(content); + var tagName = element.tagName.toUpperCase(); + + if (tagName in Element._insertionTranslations.tags) { + $A(element.childNodes).each(function(node) { element.removeChild(node) }); + Element._getContentFromAnonymousElement(tagName, content.stripScripts()) + .each(function(node) { element.appendChild(node) }); + } + else element.innerHTML = content.stripScripts(); + + content.evalScripts.bind(content).defer(); + return element; + }; +} + +if ('outerHTML' in document.createElement('div')) { + Element.Methods.replace = function(element, content) { + element = $(element); + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) { + element.parentNode.replaceChild(content, element); + return element; + } + + content = Object.toHTML(content); + var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); + + if (Element._insertionTranslations.tags[tagName]) { + var nextSibling = element.next(); + var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); + parent.removeChild(element); + if (nextSibling) + fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); + else + fragments.each(function(node) { parent.appendChild(node) }); + } + else element.outerHTML = content.stripScripts(); + + content.evalScripts.bind(content).defer(); + return element; + }; +} + +Element._returnOffset = function(l, t) { + var result = [l, t]; + result.left = l; + result.top = t; + return result; +}; + +Element._getContentFromAnonymousElement = function(tagName, html) { + var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; + if (t) { + div.innerHTML = t[0] + html + t[1]; + t[2].times(function() { div = div.firstChild }); + } else div.innerHTML = html; + return $A(div.childNodes); +}; + +Element._insertionTranslations = { + before: function(element, node) { + element.parentNode.insertBefore(node, element); + }, + top: function(element, node) { + element.insertBefore(node, element.firstChild); + }, + bottom: function(element, node) { + element.appendChild(node); + }, + after: function(element, node) { + element.parentNode.insertBefore(node, element.nextSibling); + }, + tags: { + TABLE: ['', '
', 1], + TBODY: ['', '
', 2], + TR: ['', '
', 3], + TD: ['
', '
', 4], + SELECT: ['', 1] + } +}; + +(function() { + Object.extend(this.tags, { + THEAD: this.tags.TBODY, + TFOOT: this.tags.TBODY, + TH: this.tags.TD + }); +}).call(Element._insertionTranslations); + +Element.Methods.Simulated = { + hasAttribute: function(element, attribute) { + attribute = Element._attributeTranslations.has[attribute] || attribute; + var node = $(element).getAttributeNode(attribute); + return !!(node && node.specified); + } +}; + +Element.Methods.ByTag = { }; + +Object.extend(Element, Element.Methods); + +if (!Prototype.BrowserFeatures.ElementExtensions && + document.createElement('div')['__proto__']) { + window.HTMLElement = { }; + window.HTMLElement.prototype = document.createElement('div')['__proto__']; + Prototype.BrowserFeatures.ElementExtensions = true; +} + +Element.extend = (function() { + if (Prototype.BrowserFeatures.SpecificElementExtensions) + return Prototype.K; + + var Methods = { }, ByTag = Element.Methods.ByTag; + + var extend = Object.extend(function(element) { + if (!element || element._extendedByPrototype || + element.nodeType != 1 || element == window) return element; + + var methods = Object.clone(Methods), + tagName = element.tagName.toUpperCase(), property, value; + + // extend methods for specific tags + if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); + + for (property in methods) { + value = methods[property]; + if (Object.isFunction(value) && !(property in element)) + element[property] = value.methodize(); + } + + element._extendedByPrototype = Prototype.emptyFunction; + return element; + + }, { + refresh: function() { + // extend methods for all tags (Safari doesn't need this) + if (!Prototype.BrowserFeatures.ElementExtensions) { + Object.extend(Methods, Element.Methods); + Object.extend(Methods, Element.Methods.Simulated); + } + } + }); + + extend.refresh(); + return extend; +})(); + +Element.hasAttribute = function(element, attribute) { + if (element.hasAttribute) return element.hasAttribute(attribute); + return Element.Methods.Simulated.hasAttribute(element, attribute); +}; + +Element.addMethods = function(methods) { + var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; + + if (!methods) { + Object.extend(Form, Form.Methods); + Object.extend(Form.Element, Form.Element.Methods); + Object.extend(Element.Methods.ByTag, { + "FORM": Object.clone(Form.Methods), + "INPUT": Object.clone(Form.Element.Methods), + "SELECT": Object.clone(Form.Element.Methods), + "TEXTAREA": Object.clone(Form.Element.Methods) + }); + } + + if (arguments.length == 2) { + var tagName = methods; + methods = arguments[1]; + } + + if (!tagName) Object.extend(Element.Methods, methods || { }); + else { + if (Object.isArray(tagName)) tagName.each(extend); + else extend(tagName); + } + + function extend(tagName) { + tagName = tagName.toUpperCase(); + if (!Element.Methods.ByTag[tagName]) + Element.Methods.ByTag[tagName] = { }; + Object.extend(Element.Methods.ByTag[tagName], methods); + } + + function copy(methods, destination, onlyIfAbsent) { + onlyIfAbsent = onlyIfAbsent || false; + for (var property in methods) { + var value = methods[property]; + if (!Object.isFunction(value)) continue; + if (!onlyIfAbsent || !(property in destination)) + destination[property] = value.methodize(); + } + } + + function findDOMClass(tagName) { + var klass; + var trans = { + "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", + "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", + "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", + "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", + "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": + "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": + "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": + "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": + "FrameSet", "IFRAME": "IFrame" + }; + if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; + if (window[klass]) return window[klass]; + klass = 'HTML' + tagName + 'Element'; + if (window[klass]) return window[klass]; + klass = 'HTML' + tagName.capitalize() + 'Element'; + if (window[klass]) return window[klass]; + + window[klass] = { }; + window[klass].prototype = document.createElement(tagName)['__proto__']; + return window[klass]; + } + + if (F.ElementExtensions) { + copy(Element.Methods, HTMLElement.prototype); + copy(Element.Methods.Simulated, HTMLElement.prototype, true); + } + + if (F.SpecificElementExtensions) { + for (var tag in Element.Methods.ByTag) { + var klass = findDOMClass(tag); + if (Object.isUndefined(klass)) continue; + copy(T[tag], klass.prototype); + } + } + + Object.extend(Element, Element.Methods); + delete Element.ByTag; + + if (Element.extend.refresh) Element.extend.refresh(); + Element.cache = { }; +}; + +document.viewport = { + getDimensions: function() { + var dimensions = { }, B = Prototype.Browser; + $w('width height').each(function(d) { + var D = d.capitalize(); + if (B.WebKit && !document.evaluate) { + // Safari <3.0 needs self.innerWidth/Height + dimensions[d] = self['inner' + D]; + } else if (B.Opera && parseFloat(window.opera.version()) < 9.5) { + // Opera <9.5 needs document.body.clientWidth/Height + dimensions[d] = document.body['client' + D] + } else { + dimensions[d] = document.documentElement['client' + D]; + } + }); + return dimensions; + }, + + getWidth: function() { + return this.getDimensions().width; + }, + + getHeight: function() { + return this.getDimensions().height; + }, + + getScrollOffsets: function() { + return Element._returnOffset( + window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, + window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); + } +}; +/* Portions of the Selector class are derived from Jack Slocum's DomQuery, + * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style + * license. Please see http://www.yui-ext.com/ for more information. */ + +var Selector = Class.create({ + initialize: function(expression) { + this.expression = expression.strip(); + + if (this.shouldUseSelectorsAPI()) { + this.mode = 'selectorsAPI'; + } else if (this.shouldUseXPath()) { + this.mode = 'xpath'; + this.compileXPathMatcher(); + } else { + this.mode = "normal"; + this.compileMatcher(); + } + + }, + + shouldUseXPath: function() { + if (!Prototype.BrowserFeatures.XPath) return false; + + var e = this.expression; + + // Safari 3 chokes on :*-of-type and :empty + if (Prototype.Browser.WebKit && + (e.include("-of-type") || e.include(":empty"))) + return false; + + // XPath can't do namespaced attributes, nor can it read + // the "checked" property from DOM nodes + if ((/(\[[\w-]*?:|:checked)/).test(e)) + return false; + + return true; + }, + + shouldUseSelectorsAPI: function() { + if (!Prototype.BrowserFeatures.SelectorsAPI) return false; + + if (!Selector._div) Selector._div = new Element('div'); + + // Make sure the browser treats the selector as valid. Test on an + // isolated element to minimize cost of this check. + try { + Selector._div.querySelector(this.expression); + } catch(e) { + return false; + } + + return true; + }, + + compileMatcher: function() { + var e = this.expression, ps = Selector.patterns, h = Selector.handlers, + c = Selector.criteria, le, p, m; + + if (Selector._cache[e]) { + this.matcher = Selector._cache[e]; + return; + } + + this.matcher = ["this.matcher = function(root) {", + "var r = root, h = Selector.handlers, c = false, n;"]; + + while (e && le != e && (/\S/).test(e)) { + le = e; + for (var i in ps) { + p = ps[i]; + if (m = e.match(p)) { + this.matcher.push(Object.isFunction(c[i]) ? c[i](m) : + new Template(c[i]).evaluate(m)); + e = e.replace(m[0], ''); + break; + } + } + } + + this.matcher.push("return h.unique(n);\n}"); + eval(this.matcher.join('\n')); + Selector._cache[this.expression] = this.matcher; + }, + + compileXPathMatcher: function() { + var e = this.expression, ps = Selector.patterns, + x = Selector.xpath, le, m; + + if (Selector._cache[e]) { + this.xpath = Selector._cache[e]; return; + } + + this.matcher = ['.//*']; + while (e && le != e && (/\S/).test(e)) { + le = e; + for (var i in ps) { + if (m = e.match(ps[i])) { + this.matcher.push(Object.isFunction(x[i]) ? x[i](m) : + new Template(x[i]).evaluate(m)); + e = e.replace(m[0], ''); + break; + } + } + } + + this.xpath = this.matcher.join(''); + Selector._cache[this.expression] = this.xpath; + }, + + findElements: function(root) { + root = root || document; + var e = this.expression, results; + + switch (this.mode) { + case 'selectorsAPI': + // querySelectorAll queries document-wide, then filters to descendants + // of the context element. That's not what we want. + // Add an explicit context to the selector if necessary. + if (root !== document) { + var oldId = root.id, id = $(root).identify(); + e = "#" + id + " " + e; + } + + results = $A(root.querySelectorAll(e)).map(Element.extend); + root.id = oldId; + + return results; + case 'xpath': + return document._getElementsByXPath(this.xpath, root); + default: + return this.matcher(root); + } + }, + + match: function(element) { + this.tokens = []; + + var e = this.expression, ps = Selector.patterns, as = Selector.assertions; + var le, p, m; + + while (e && le !== e && (/\S/).test(e)) { + le = e; + for (var i in ps) { + p = ps[i]; + if (m = e.match(p)) { + // use the Selector.assertions methods unless the selector + // is too complex. + if (as[i]) { + this.tokens.push([i, Object.clone(m)]); + e = e.replace(m[0], ''); + } else { + // reluctantly do a document-wide search + // and look for a match in the array + return this.findElements(document).include(element); + } + } + } + } + + var match = true, name, matches; + for (var i = 0, token; token = this.tokens[i]; i++) { + name = token[0], matches = token[1]; + if (!Selector.assertions[name](element, matches)) { + match = false; break; + } + } + + return match; + }, + + toString: function() { + return this.expression; + }, + + inspect: function() { + return "#"; + } +}); + +Object.extend(Selector, { + _cache: { }, + + xpath: { + descendant: "//*", + child: "/*", + adjacent: "/following-sibling::*[1]", + laterSibling: '/following-sibling::*', + tagName: function(m) { + if (m[1] == '*') return ''; + return "[local-name()='" + m[1].toLowerCase() + + "' or local-name()='" + m[1].toUpperCase() + "']"; + }, + className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", + id: "[@id='#{1}']", + attrPresence: function(m) { + m[1] = m[1].toLowerCase(); + return new Template("[@#{1}]").evaluate(m); + }, + attr: function(m) { + m[1] = m[1].toLowerCase(); + m[3] = m[5] || m[6]; + return new Template(Selector.xpath.operators[m[2]]).evaluate(m); + }, + pseudo: function(m) { + var h = Selector.xpath.pseudos[m[1]]; + if (!h) return ''; + if (Object.isFunction(h)) return h(m); + return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); + }, + operators: { + '=': "[@#{1}='#{3}']", + '!=': "[@#{1}!='#{3}']", + '^=': "[starts-with(@#{1}, '#{3}')]", + '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", + '*=': "[contains(@#{1}, '#{3}')]", + '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", + '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" + }, + pseudos: { + 'first-child': '[not(preceding-sibling::*)]', + 'last-child': '[not(following-sibling::*)]', + 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', + 'empty': "[count(*) = 0 and (count(text()) = 0)]", + 'checked': "[@checked]", + 'disabled': "[(@disabled) and (@type!='hidden')]", + 'enabled': "[not(@disabled) and (@type!='hidden')]", + 'not': function(m) { + var e = m[6], p = Selector.patterns, + x = Selector.xpath, le, v; + + var exclusion = []; + while (e && le != e && (/\S/).test(e)) { + le = e; + for (var i in p) { + if (m = e.match(p[i])) { + v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m); + exclusion.push("(" + v.substring(1, v.length - 1) + ")"); + e = e.replace(m[0], ''); + break; + } + } + } + return "[not(" + exclusion.join(" and ") + ")]"; + }, + 'nth-child': function(m) { + return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m); + }, + 'nth-last-child': function(m) { + return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m); + }, + 'nth-of-type': function(m) { + return Selector.xpath.pseudos.nth("position() ", m); + }, + 'nth-last-of-type': function(m) { + return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m); + }, + 'first-of-type': function(m) { + m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m); + }, + 'last-of-type': function(m) { + m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m); + }, + 'only-of-type': function(m) { + var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m); + }, + nth: function(fragment, m) { + var mm, formula = m[6], predicate; + if (formula == 'even') formula = '2n+0'; + if (formula == 'odd') formula = '2n+1'; + if (mm = formula.match(/^(\d+)$/)) // digit only + return '[' + fragment + "= " + mm[1] + ']'; + if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b + if (mm[1] == "-") mm[1] = -1; + var a = mm[1] ? Number(mm[1]) : 1; + var b = mm[2] ? Number(mm[2]) : 0; + predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " + + "((#{fragment} - #{b}) div #{a} >= 0)]"; + return new Template(predicate).evaluate({ + fragment: fragment, a: a, b: b }); + } + } + } + }, + + criteria: { + tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', + className: 'n = h.className(n, r, "#{1}", c); c = false;', + id: 'n = h.id(n, r, "#{1}", c); c = false;', + attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;', + attr: function(m) { + m[3] = (m[5] || m[6]); + return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m); + }, + pseudo: function(m) { + if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); + return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); + }, + descendant: 'c = "descendant";', + child: 'c = "child";', + adjacent: 'c = "adjacent";', + laterSibling: 'c = "laterSibling";' + }, + + patterns: { + // combinators must be listed first + // (and descendant needs to be last combinator) + laterSibling: /^\s*~\s*/, + child: /^\s*>\s*/, + adjacent: /^\s*\+\s*/, + descendant: /^\s/, + + // selectors follow + tagName: /^\s*(\*|[\w\-]+)(\b|$)?/, + id: /^#([\w\-\*]+)(\b|$)/, + className: /^\.([\w\-\*]+)(\b|$)/, + pseudo: +/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/, + attrPresence: /^\[((?:[\w]+:)?[\w]+)\]/, + attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ + }, + + // for Selector.match and Element#match + assertions: { + tagName: function(element, matches) { + return matches[1].toUpperCase() == element.tagName.toUpperCase(); + }, + + className: function(element, matches) { + return Element.hasClassName(element, matches[1]); + }, + + id: function(element, matches) { + return element.id === matches[1]; + }, + + attrPresence: function(element, matches) { + return Element.hasAttribute(element, matches[1]); + }, + + attr: function(element, matches) { + var nodeValue = Element.readAttribute(element, matches[1]); + return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]); + } + }, + + handlers: { + // UTILITY FUNCTIONS + // joins two collections + concat: function(a, b) { + for (var i = 0, node; node = b[i]; i++) + a.push(node); + return a; + }, + + // marks an array of nodes for counting + mark: function(nodes) { + var _true = Prototype.emptyFunction; + for (var i = 0, node; node = nodes[i]; i++) + node._countedByPrototype = _true; + return nodes; + }, + + unmark: function(nodes) { + for (var i = 0, node; node = nodes[i]; i++) + node._countedByPrototype = undefined; + return nodes; + }, + + // mark each child node with its position (for nth calls) + // "ofType" flag indicates whether we're indexing for nth-of-type + // rather than nth-child + index: function(parentNode, reverse, ofType) { + parentNode._countedByPrototype = Prototype.emptyFunction; + if (reverse) { + for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { + var node = nodes[i]; + if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; + } + } else { + for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) + if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; + } + }, + + // filters out duplicates and extends all nodes + unique: function(nodes) { + if (nodes.length == 0) return nodes; + var results = [], n; + for (var i = 0, l = nodes.length; i < l; i++) + if (!(n = nodes[i])._countedByPrototype) { + n._countedByPrototype = Prototype.emptyFunction; + results.push(Element.extend(n)); + } + return Selector.handlers.unmark(results); + }, + + // COMBINATOR FUNCTIONS + descendant: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + h.concat(results, node.getElementsByTagName('*')); + return results; + }, + + child: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) { + for (var j = 0, child; child = node.childNodes[j]; j++) + if (child.nodeType == 1 && child.tagName != '!') results.push(child); + } + return results; + }, + + adjacent: function(nodes) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + var next = this.nextElementSibling(node); + if (next) results.push(next); + } + return results; + }, + + laterSibling: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + h.concat(results, Element.nextSiblings(node)); + return results; + }, + + nextElementSibling: function(node) { + while (node = node.nextSibling) + if (node.nodeType == 1) return node; + return null; + }, + + previousElementSibling: function(node) { + while (node = node.previousSibling) + if (node.nodeType == 1) return node; + return null; + }, + + // TOKEN FUNCTIONS + tagName: function(nodes, root, tagName, combinator) { + var uTagName = tagName.toUpperCase(); + var results = [], h = Selector.handlers; + if (nodes) { + if (combinator) { + // fastlane for ordinary descendant combinators + if (combinator == "descendant") { + for (var i = 0, node; node = nodes[i]; i++) + h.concat(results, node.getElementsByTagName(tagName)); + return results; + } else nodes = this[combinator](nodes); + if (tagName == "*") return nodes; + } + for (var i = 0, node; node = nodes[i]; i++) + if (node.tagName.toUpperCase() === uTagName) results.push(node); + return results; + } else return root.getElementsByTagName(tagName); + }, + + id: function(nodes, root, id, combinator) { + var targetNode = $(id), h = Selector.handlers; + if (!targetNode) return []; + if (!nodes && root == document) return [targetNode]; + if (nodes) { + if (combinator) { + if (combinator == 'child') { + for (var i = 0, node; node = nodes[i]; i++) + if (targetNode.parentNode == node) return [targetNode]; + } else if (combinator == 'descendant') { + for (var i = 0, node; node = nodes[i]; i++) + if (Element.descendantOf(targetNode, node)) return [targetNode]; + } else if (combinator == 'adjacent') { + for (var i = 0, node; node = nodes[i]; i++) + if (Selector.handlers.previousElementSibling(targetNode) == node) + return [targetNode]; + } else nodes = h[combinator](nodes); + } + for (var i = 0, node; node = nodes[i]; i++) + if (node == targetNode) return [targetNode]; + return []; + } + return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; + }, + + className: function(nodes, root, className, combinator) { + if (nodes && combinator) nodes = this[combinator](nodes); + return Selector.handlers.byClassName(nodes, root, className); + }, + + byClassName: function(nodes, root, className) { + if (!nodes) nodes = Selector.handlers.descendant([root]); + var needle = ' ' + className + ' '; + for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { + nodeClassName = node.className; + if (nodeClassName.length == 0) continue; + if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) + results.push(node); + } + return results; + }, + + attrPresence: function(nodes, root, attr, combinator) { + if (!nodes) nodes = root.getElementsByTagName("*"); + if (nodes && combinator) nodes = this[combinator](nodes); + var results = []; + for (var i = 0, node; node = nodes[i]; i++) + if (Element.hasAttribute(node, attr)) results.push(node); + return results; + }, + + attr: function(nodes, root, attr, value, operator, combinator) { + if (!nodes) nodes = root.getElementsByTagName("*"); + if (nodes && combinator) nodes = this[combinator](nodes); + var handler = Selector.operators[operator], results = []; + for (var i = 0, node; node = nodes[i]; i++) { + var nodeValue = Element.readAttribute(node, attr); + if (nodeValue === null) continue; + if (handler(nodeValue, value)) results.push(node); + } + return results; + }, + + pseudo: function(nodes, name, value, root, combinator) { + if (nodes && combinator) nodes = this[combinator](nodes); + if (!nodes) nodes = root.getElementsByTagName("*"); + return Selector.pseudos[name](nodes, value, root); + } + }, + + pseudos: { + 'first-child': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + if (Selector.handlers.previousElementSibling(node)) continue; + results.push(node); + } + return results; + }, + 'last-child': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + if (Selector.handlers.nextElementSibling(node)) continue; + results.push(node); + } + return results; + }, + 'only-child': function(nodes, value, root) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) + results.push(node); + return results; + }, + 'nth-child': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root); + }, + 'nth-last-child': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, true); + }, + 'nth-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, false, true); + }, + 'nth-last-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, true, true); + }, + 'first-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, "1", root, false, true); + }, + 'last-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, "1", root, true, true); + }, + 'only-of-type': function(nodes, formula, root) { + var p = Selector.pseudos; + return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); + }, + + // handles the an+b logic + getIndices: function(a, b, total) { + if (a == 0) return b > 0 ? [b] : []; + return $R(1, total).inject([], function(memo, i) { + if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); + return memo; + }); + }, + + // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type + nth: function(nodes, formula, root, reverse, ofType) { + if (nodes.length == 0) return []; + if (formula == 'even') formula = '2n+0'; + if (formula == 'odd') formula = '2n+1'; + var h = Selector.handlers, results = [], indexed = [], m; + h.mark(nodes); + for (var i = 0, node; node = nodes[i]; i++) { + if (!node.parentNode._countedByPrototype) { + h.index(node.parentNode, reverse, ofType); + indexed.push(node.parentNode); + } + } + if (formula.match(/^\d+$/)) { // just a number + formula = Number(formula); + for (var i = 0, node; node = nodes[i]; i++) + if (node.nodeIndex == formula) results.push(node); + } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b + if (m[1] == "-") m[1] = -1; + var a = m[1] ? Number(m[1]) : 1; + var b = m[2] ? Number(m[2]) : 0; + var indices = Selector.pseudos.getIndices(a, b, nodes.length); + for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { + for (var j = 0; j < l; j++) + if (node.nodeIndex == indices[j]) results.push(node); + } + } + h.unmark(nodes); + h.unmark(indexed); + return results; + }, + + 'empty': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + // IE treats comments as element nodes + if (node.tagName == '!' || node.firstChild) continue; + results.push(node); + } + return results; + }, + + 'not': function(nodes, selector, root) { + var h = Selector.handlers, selectorType, m; + var exclusions = new Selector(selector).findElements(root); + h.mark(exclusions); + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!node._countedByPrototype) results.push(node); + h.unmark(exclusions); + return results; + }, + + 'enabled': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!node.disabled && (!node.type || node.type !== 'hidden')) + results.push(node); + return results; + }, + + 'disabled': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (node.disabled) results.push(node); + return results; + }, + + 'checked': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (node.checked) results.push(node); + return results; + } + }, + + operators: { + '=': function(nv, v) { return nv == v; }, + '!=': function(nv, v) { return nv != v; }, + '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); }, + '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); }, + '*=': function(nv, v) { return nv == v || nv && nv.include(v); }, + '$=': function(nv, v) { return nv.endsWith(v); }, + '*=': function(nv, v) { return nv.include(v); }, + '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, + '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() + + '-').include('-' + (v || "").toUpperCase() + '-'); } + }, + + split: function(expression) { + var expressions = []; + expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { + expressions.push(m[1].strip()); + }); + return expressions; + }, + + matchElements: function(elements, expression) { + var matches = $$(expression), h = Selector.handlers; + h.mark(matches); + for (var i = 0, results = [], element; element = elements[i]; i++) + if (element._countedByPrototype) results.push(element); + h.unmark(matches); + return results; + }, + + findElement: function(elements, expression, index) { + if (Object.isNumber(expression)) { + index = expression; expression = false; + } + return Selector.matchElements(elements, expression || '*')[index || 0]; + }, + + findChildElements: function(element, expressions) { + expressions = Selector.split(expressions.join(',')); + var results = [], h = Selector.handlers; + for (var i = 0, l = expressions.length, selector; i < l; i++) { + selector = new Selector(expressions[i].strip()); + h.concat(results, selector.findElements(element)); + } + return (l > 1) ? h.unique(results) : results; + } +}); + +if (Prototype.Browser.IE) { + Object.extend(Selector.handlers, { + // IE returns comment nodes on getElementsByTagName("*"). + // Filter them out. + concat: function(a, b) { + for (var i = 0, node; node = b[i]; i++) + if (node.tagName !== "!") a.push(node); + return a; + }, + + // IE improperly serializes _countedByPrototype in (inner|outer)HTML. + unmark: function(nodes) { + for (var i = 0, node; node = nodes[i]; i++) + node.removeAttribute('_countedByPrototype'); + return nodes; + } + }); +} + +function $$() { + return Selector.findChildElements(document, $A(arguments)); +} +var Form = { + reset: function(form) { + $(form).reset(); + return form; + }, + + serializeElements: function(elements, options) { + if (typeof options != 'object') options = { hash: !!options }; + else if (Object.isUndefined(options.hash)) options.hash = true; + var key, value, submitted = false, submit = options.submit; + + var data = elements.inject({ }, function(result, element) { + if (!element.disabled && element.name) { + key = element.name; value = $(element).getValue(); + if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted && + submit !== false && (!submit || key == submit) && (submitted = true)))) { + if (key in result) { + // a key is already present; construct an array of values + if (!Object.isArray(result[key])) result[key] = [result[key]]; + result[key].push(value); + } + else result[key] = value; + } + } + return result; + }); + + return options.hash ? data : Object.toQueryString(data); + } +}; + +Form.Methods = { + serialize: function(form, options) { + return Form.serializeElements(Form.getElements(form), options); + }, + + getElements: function(form) { + return $A($(form).getElementsByTagName('*')).inject([], + function(elements, child) { + if (Form.Element.Serializers[child.tagName.toLowerCase()]) + elements.push(Element.extend(child)); + return elements; + } + ); + }, + + getInputs: function(form, typeName, name) { + form = $(form); + var inputs = form.getElementsByTagName('input'); + + if (!typeName && !name) return $A(inputs).map(Element.extend); + + for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { + var input = inputs[i]; + if ((typeName && input.type != typeName) || (name && input.name != name)) + continue; + matchingInputs.push(Element.extend(input)); + } + + return matchingInputs; + }, + + disable: function(form) { + form = $(form); + Form.getElements(form).invoke('disable'); + return form; + }, + + enable: function(form) { + form = $(form); + Form.getElements(form).invoke('enable'); + return form; + }, + + findFirstElement: function(form) { + var elements = $(form).getElements().findAll(function(element) { + return 'hidden' != element.type && !element.disabled; + }); + var firstByIndex = elements.findAll(function(element) { + return element.hasAttribute('tabIndex') && element.tabIndex >= 0; + }).sortBy(function(element) { return element.tabIndex }).first(); + + return firstByIndex ? firstByIndex : elements.find(function(element) { + return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); + }); + }, + + focusFirstElement: function(form) { + form = $(form); + form.findFirstElement().activate(); + return form; + }, + + request: function(form, options) { + form = $(form), options = Object.clone(options || { }); + + var params = options.parameters, action = form.readAttribute('action') || ''; + if (action.blank()) action = window.location.href; + options.parameters = form.serialize(true); + + if (params) { + if (Object.isString(params)) params = params.toQueryParams(); + Object.extend(options.parameters, params); + } + + if (form.hasAttribute('method') && !options.method) + options.method = form.method; + + return new Ajax.Request(action, options); + } +}; + +/*--------------------------------------------------------------------------*/ + +Form.Element = { + focus: function(element) { + $(element).focus(); + return element; + }, + + select: function(element) { + $(element).select(); + return element; + } +}; + +Form.Element.Methods = { + serialize: function(element) { + element = $(element); + if (!element.disabled && element.name) { + var value = element.getValue(); + if (value != undefined) { + var pair = { }; + pair[element.name] = value; + return Object.toQueryString(pair); + } + } + return ''; + }, + + getValue: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + return Form.Element.Serializers[method](element); + }, + + setValue: function(element, value) { + element = $(element); + var method = element.tagName.toLowerCase(); + Form.Element.Serializers[method](element, value); + return element; + }, + + clear: function(element) { + $(element).value = ''; + return element; + }, + + present: function(element) { + return $(element).value != ''; + }, + + activate: function(element) { + element = $(element); + try { + element.focus(); + if (element.select && (element.tagName.toLowerCase() != 'input' || + !['button', 'reset', 'submit'].include(element.type))) + element.select(); + } catch (e) { } + return element; + }, + + disable: function(element) { + element = $(element); + element.disabled = true; + return element; + }, + + enable: function(element) { + element = $(element); + element.disabled = false; + return element; + } +}; + +/*--------------------------------------------------------------------------*/ + +var Field = Form.Element; +var $F = Form.Element.Methods.getValue; + +/*--------------------------------------------------------------------------*/ + +Form.Element.Serializers = { + input: function(element, value) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + return Form.Element.Serializers.inputSelector(element, value); + default: + return Form.Element.Serializers.textarea(element, value); + } + }, + + inputSelector: function(element, value) { + if (Object.isUndefined(value)) return element.checked ? element.value : null; + else element.checked = !!value; + }, + + textarea: function(element, value) { + if (Object.isUndefined(value)) return element.value; + else element.value = value; + }, + + select: function(element, value) { + if (Object.isUndefined(value)) + return this[element.type == 'select-one' ? + 'selectOne' : 'selectMany'](element); + else { + var opt, currentValue, single = !Object.isArray(value); + for (var i = 0, length = element.length; i < length; i++) { + opt = element.options[i]; + currentValue = this.optionValue(opt); + if (single) { + if (currentValue == value) { + opt.selected = true; + return; + } + } + else opt.selected = value.include(currentValue); + } + } + }, + + selectOne: function(element) { + var index = element.selectedIndex; + return index >= 0 ? this.optionValue(element.options[index]) : null; + }, + + selectMany: function(element) { + var values, length = element.length; + if (!length) return null; + + for (var i = 0, values = []; i < length; i++) { + var opt = element.options[i]; + if (opt.selected) values.push(this.optionValue(opt)); + } + return values; + }, + + optionValue: function(opt) { + // extend element because hasAttribute may not be native + return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; + } +}; + +/*--------------------------------------------------------------------------*/ + +Abstract.TimedObserver = Class.create(PeriodicalExecuter, { + initialize: function($super, element, frequency, callback) { + $super(callback, frequency); + this.element = $(element); + this.lastValue = this.getValue(); + }, + + execute: function() { + var value = this.getValue(); + if (Object.isString(this.lastValue) && Object.isString(value) ? + this.lastValue != value : String(this.lastValue) != String(value)) { + this.callback(this.element, value); + this.lastValue = value; + } + } +}); + +Form.Element.Observer = Class.create(Abstract.TimedObserver, { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.Observer = Class.create(Abstract.TimedObserver, { + getValue: function() { + return Form.serialize(this.element); + } +}); + +/*--------------------------------------------------------------------------*/ + +Abstract.EventObserver = Class.create({ + initialize: function(element, callback) { + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + if (this.element.tagName.toLowerCase() == 'form') + this.registerFormCallbacks(); + else + this.registerCallback(this.element); + }, + + onElementEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + }, + + registerFormCallbacks: function() { + Form.getElements(this.element).each(this.registerCallback, this); + }, + + registerCallback: function(element) { + if (element.type) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + Event.observe(element, 'click', this.onElementEvent.bind(this)); + break; + default: + Event.observe(element, 'change', this.onElementEvent.bind(this)); + break; + } + } + } +}); + +Form.Element.EventObserver = Class.create(Abstract.EventObserver, { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.EventObserver = Class.create(Abstract.EventObserver, { + getValue: function() { + return Form.serialize(this.element); + } +}); +if (!window.Event) var Event = { }; + +Object.extend(Event, { + KEY_BACKSPACE: 8, + KEY_TAB: 9, + KEY_RETURN: 13, + KEY_ESC: 27, + KEY_LEFT: 37, + KEY_UP: 38, + KEY_RIGHT: 39, + KEY_DOWN: 40, + KEY_DELETE: 46, + KEY_HOME: 36, + KEY_END: 35, + KEY_PAGEUP: 33, + KEY_PAGEDOWN: 34, + KEY_INSERT: 45, + + cache: { }, + + relatedTarget: function(event) { + var element; + switch(event.type) { + case 'mouseover': element = event.fromElement; break; + case 'mouseout': element = event.toElement; break; + default: return null; + } + return Element.extend(element); + } +}); + +Event.Methods = (function() { + var isButton; + + if (Prototype.Browser.IE) { + var buttonMap = { 0: 1, 1: 4, 2: 2 }; + isButton = function(event, code) { + return event.button == buttonMap[code]; + }; + + } else if (Prototype.Browser.WebKit) { + isButton = function(event, code) { + switch (code) { + case 0: return event.which == 1 && !event.metaKey; + case 1: return event.which == 1 && event.metaKey; + default: return false; + } + }; + + } else { + isButton = function(event, code) { + return event.which ? (event.which === code + 1) : (event.button === code); + }; + } + + return { + isLeftClick: function(event) { return isButton(event, 0) }, + isMiddleClick: function(event) { return isButton(event, 1) }, + isRightClick: function(event) { return isButton(event, 2) }, + + element: function(event) { + event = Event.extend(event); + + var node = event.target, + type = event.type, + currentTarget = event.currentTarget; + + if (currentTarget && currentTarget.tagName) { + // Firefox screws up the "click" event when moving between radio buttons + // via arrow keys. It also screws up the "load" and "error" events on images, + // reporting the document as the target instead of the original image. + if (type === 'load' || type === 'error' || + (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' + && currentTarget.type === 'radio')) + node = currentTarget; + } + if (node.nodeType == Node.TEXT_NODE) node = node.parentNode; + return Element.extend(node); + }, + + findElement: function(event, expression) { + var element = Event.element(event); + if (!expression) return element; + var elements = [element].concat(element.ancestors()); + return Selector.findElement(elements, expression, 0); + }, + + pointer: function(event) { + var docElement = document.documentElement, + body = document.body || { scrollLeft: 0, scrollTop: 0 }; + return { + x: event.pageX || (event.clientX + + (docElement.scrollLeft || body.scrollLeft) - + (docElement.clientLeft || 0)), + y: event.pageY || (event.clientY + + (docElement.scrollTop || body.scrollTop) - + (docElement.clientTop || 0)) + }; + }, + + pointerX: function(event) { return Event.pointer(event).x }, + pointerY: function(event) { return Event.pointer(event).y }, + + stop: function(event) { + Event.extend(event); + event.preventDefault(); + event.stopPropagation(); + event.stopped = true; + } + }; +})(); + +Event.extend = (function() { + var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { + m[name] = Event.Methods[name].methodize(); + return m; + }); + + if (Prototype.Browser.IE) { + Object.extend(methods, { + stopPropagation: function() { this.cancelBubble = true }, + preventDefault: function() { this.returnValue = false }, + inspect: function() { return "[object Event]" } + }); + + return function(event) { + if (!event) return false; + if (event._extendedByPrototype) return event; + + event._extendedByPrototype = Prototype.emptyFunction; + var pointer = Event.pointer(event); + Object.extend(event, { + target: event.srcElement, + relatedTarget: Event.relatedTarget(event), + pageX: pointer.x, + pageY: pointer.y + }); + return Object.extend(event, methods); + }; + + } else { + Event.prototype = Event.prototype || document.createEvent("HTMLEvents")['__proto__']; + Object.extend(Event.prototype, methods); + return Prototype.K; + } +})(); + +Object.extend(Event, (function() { + var cache = Event.cache; + + function getEventID(element) { + if (element._prototypeEventID) return element._prototypeEventID[0]; + arguments.callee.id = arguments.callee.id || 1; + return element._prototypeEventID = [++arguments.callee.id]; + } + + function getDOMEventName(eventName) { + if (eventName && eventName.include(':')) return "dataavailable"; + return eventName; + } + + function getCacheForID(id) { + return cache[id] = cache[id] || { }; + } + + function getWrappersForEventName(id, eventName) { + var c = getCacheForID(id); + return c[eventName] = c[eventName] || []; + } + + function createWrapper(element, eventName, handler) { + var id = getEventID(element); + var c = getWrappersForEventName(id, eventName); + if (c.pluck("handler").include(handler)) return false; + + var wrapper = function(event) { + if (!Event || !Event.extend || + (event.eventName && event.eventName != eventName)) + return false; + + Event.extend(event); + handler.call(element, event); + }; + + wrapper.handler = handler; + c.push(wrapper); + return wrapper; + } + + function findWrapper(id, eventName, handler) { + var c = getWrappersForEventName(id, eventName); + return c.find(function(wrapper) { return wrapper.handler == handler }); + } + + function destroyWrapper(id, eventName, handler) { + var c = getCacheForID(id); + if (!c[eventName]) return false; + c[eventName] = c[eventName].without(findWrapper(id, eventName, handler)); + } + + function destroyCache() { + for (var id in cache) + for (var eventName in cache[id]) + cache[id][eventName] = null; + } + + + // Internet Explorer needs to remove event handlers on page unload + // in order to avoid memory leaks. + if (window.attachEvent) { + window.attachEvent("onunload", destroyCache); + } + + // Safari has a dummy event handler on page unload so that it won't + // use its bfcache. Safari <= 3.1 has an issue with restoring the "document" + // object when page is returned to via the back button using its bfcache. + if (Prototype.Browser.WebKit) { + window.addEventListener('unload', Prototype.emptyFunction, false); + } + + return { + observe: function(element, eventName, handler) { + element = $(element); + var name = getDOMEventName(eventName); + + var wrapper = createWrapper(element, eventName, handler); + if (!wrapper) return element; + + if (element.addEventListener) { + element.addEventListener(name, wrapper, false); + } else { + element.attachEvent("on" + name, wrapper); + } + + return element; + }, + + stopObserving: function(element, eventName, handler) { + element = $(element); + var id = getEventID(element), name = getDOMEventName(eventName); + + if (!handler && eventName) { + getWrappersForEventName(id, eventName).each(function(wrapper) { + element.stopObserving(eventName, wrapper.handler); + }); + return element; + + } else if (!eventName) { + Object.keys(getCacheForID(id)).each(function(eventName) { + element.stopObserving(eventName); + }); + return element; + } + + var wrapper = findWrapper(id, eventName, handler); + if (!wrapper) return element; + + if (element.removeEventListener) { + element.removeEventListener(name, wrapper, false); + } else { + element.detachEvent("on" + name, wrapper); + } + + destroyWrapper(id, eventName, handler); + + return element; + }, + + fire: function(element, eventName, memo) { + element = $(element); + if (element == document && document.createEvent && !element.dispatchEvent) + element = document.documentElement; + + var event; + if (document.createEvent) { + event = document.createEvent("HTMLEvents"); + event.initEvent("dataavailable", true, true); + } else { + event = document.createEventObject(); + event.eventType = "ondataavailable"; + } + + event.eventName = eventName; + event.memo = memo || { }; + + if (document.createEvent) { + element.dispatchEvent(event); + } else { + element.fireEvent(event.eventType, event); + } + + return Event.extend(event); + } + }; +})()); + +Object.extend(Event, Event.Methods); + +Element.addMethods({ + fire: Event.fire, + observe: Event.observe, + stopObserving: Event.stopObserving +}); + +Object.extend(document, { + fire: Element.Methods.fire.methodize(), + observe: Element.Methods.observe.methodize(), + stopObserving: Element.Methods.stopObserving.methodize(), + loaded: false +}); + +(function() { + /* Support for the DOMContentLoaded event is based on work by Dan Webb, + Matthias Miller, Dean Edwards and John Resig. */ + + var timer; + + function fireContentLoadedEvent() { + if (document.loaded) return; + if (timer) window.clearInterval(timer); + document.fire("dom:loaded"); + document.loaded = true; + } + + if (document.addEventListener) { + if (Prototype.Browser.WebKit) { + timer = window.setInterval(function() { + if (/loaded|complete/.test(document.readyState)) + fireContentLoadedEvent(); + }, 0); + + Event.observe(window, "load", fireContentLoadedEvent); + + } else { + document.addEventListener("DOMContentLoaded", + fireContentLoadedEvent, false); + } + + } else { + document.write(" + + +
+ +
+ + +
+ +

Getting Started

+ +

Choose a JABAWS distribution

+ + + + + + + + + + + + + + + + + + +
I want to use JABAWS for...Quick Guide
Running Muptiple Sequence Alignments through Jalview on my own computerJABAWS Virtual Appliance (VA)
Running JABAWS for my group, lab, or organizationJABAWS Web Application aRchive (WAR)
Accessing a JABAWS server from my own codeJABAWS Java Client
+ + + + + + +
+ + +
+
+ + + + + + + diff --git a/website/ws.css b/website/ws.css new file mode 100644 index 0000000..5d9156c --- /dev/null +++ b/website/ws.css @@ -0,0 +1,379 @@ + +#banner { background-color:white; } + +#mainpagefeatures { + margin: 0 2em 0 2em; +} + +#wrapper #mainpagefeatures table, #wrapper #mainpagefeatures th, #wrapper #mainpagefeatures td, #wrapper #mainpagefeatures tr{ + border:none; + border-collapse:collapse; + background-color: #fff; + padding-bottom:2em; +} + +#wrapper #choicematrix table, #wrapper #choicematrix th, #wrapper #choicematrix td, #wrapper #choicematrix tr{ + border:1px solid grey; + background-color: #fff; + padding:1em; +} + +#wrapper #choicematrix th { + background-image:url(images/brickhead2.jpg); + background-repeat:repeat-x; +} + +.brick { +padding-bottom:1em; + border: 2px solid #999; + -webkit-border-radius:20px; + -moz-border-radius:20px; + border-radius: 20px; + background-image:url(images/brickhead2_line.jpg); + background-repeat:repeat-x; +} +.brick_header { + display:block; + background:none; +} + +.brick_header h2 { + font-weight: bold; + border:none; + background:none; + margin: 0.7em 0 0 0.5em; +} + +.brick_content { + position:relative; + padding: 2em 1.5em 0em 1.5em; +} + + +/* +td.vm { +background-image:url(images/N_cell.jpg); +background-repeat:repeat-x; +} +td.button a { +display:block; +background:#069; +border:1px outset #069; +text-decoration:none; +font-weight:bold; +line-height:1.5em; +padding:0 .5em; +color:#fff; +} + +td.button a:hover { +background:#09c; +border-color:09c; +} +*/ +#container .round { + display:block; + margin-right:10px; + background:#fff; + border: 1px solid #ccc; + -webkit-border-radius:20px; + -moz-border-radius:20px; + border-radius: 20px; + background-image:url(images/N_cell.jpg); + background-repeat:repeat-x; +} + + /* +#container .example5 div a { + padding:3px 20px; + border: 1px solid #ccc; + -webkit-border-radius:20px; + -moz-border-radius:15px; +} + +#container .example5 div a:hover { + background:#5d9ddd; + border:1px solid #2a7ecd; + color:#fff; +} +*/ +/* + + -webkit-border-radius:20px; + -moz-border-radius:15px; + +See index.html banner commented out code for an example of use +.uniicon { overflow: hidden; display:inline; padding:0; margin:0; float:right; position:relative; top:1em; } +.uniicon a img {border:none;} +*/ +#panel { + width:150px; + background:url("images/panel_bg.gif") repeat-y ; + float:left; + font-family:Verdana, Arial, Helvetica, sans-serif; + padding-top:1em; + } + +#content { + margin-left:157px; + border-bottom:solid 1px #6994af; + margin-right:0.9em; +} + +#page { + margin: 0; + background-color:#fff; +} + +#copyright { text-align:right; + color:#999999; + font-family:Verdana, Arial, Helvetica, sans-serif; + font-size:smaller; + line-height:1em; + padding:0.3em 0.9em 1em 0; + } + +#wrapper { + background:url("images/panel_bg.gif") repeat-y left top; + margin:0; + padding:0; +} + +ul { + list-style-type: circle; +} + +#panel a:link, #panel a:visited { + text-decoration: none; + display:block; + line-height: 1em; + padding:10px; + color:#000000; + } + +#panel a:hover { + background-color: transparent; + text-decoration: underline; + } + +#panel a.selected { + text-decoration:underline; + font-weight:bolder; +} + + +#panel #submenu a { +margin-left: 1.5em; +margin-left: 20px; +padding: 5px; +} + +strong { + font-weight:bold; + color:#003366; +} + +pre { + font-family:Arial, Helvetica, sans-serif; +} + +p { + line-height: 1.4em; +} + +.hightlight { +font-style:italic; +font-family:"Courier New", Courier, monospace; +} + + +/* +.about { +border-left: solid 4px #006633; +border-left-style:ridged; +padding-left: 1em; +}*/ + + +.code { + color:black; + background-color:#F5F5F5; + font-family:"Courier New",Courier,monospace; + font-style:normal; + margin:1em 0; + padding: 0.5em; + border: 1px dashed black; + display:block; +} + +.box { + color:black; + background-color:#F5F5F5; + font-family:Arial, Helvetica, sans-serif; + font-style:normal; + margin:1em 0; + padding: 0.5em; + border: 1px solid black; + display:block; +} + +.u { text-decoration: underline; } +/* .headeru { text-shadow: #CCCCCC 15px -14px 2px;} font-size-adjust:+0.7 */ +/*.headeru { text-shadow: 1px 0 black, 0 -1px black;} */ +.headeru { + text-shadow:0 1px 3px black; + border-bottom: 1px solid white; +} +/* .headeru { border-bottom:1px solid white; } */ + +#banner h1 { + font-family:Helvetica, Arial, sans-serif; + white-space:nowrap; + color: white; + font-weight:bold; + text-shadow:0 1px 3px #100F0E; + font-size: 27px; +} + +h3 {border-bottom: 1px solid grey; margin-top: 2em; } + +#headtitle { margin:0; padding-top:1em; text-align:center; color:#003b62; font-weight:600;} + +h2 {margin:1.8em 0 0 0; color:#003b62; font-weight:600;} + +/* Table styles */ + +#wrapper table { + border-collapse: collapse; + border: 1px solid #666; + margin: 20px 0 20px 0; + width: 100%; +} +#wrapper th, #wrapper td { + margin: 2px 4px 2px 4px; + padding: 0 5px; + text-align: left; + vertical-align: top; + border: 1px solid #666; +} + +#wrapper table caption { + font: 1.5em Georgia, "Times New Roman", Times, serif; + padding: 1em; + background-color: #9c9; +} + + +#wrapper tr { + background-color: #eee; +} + +#wrapper tr:nth-child(odd) { + background-color: #ccc; +} + +span.directory { +background: transparent url(images/dir.gif) no-repeat scroll left center; +color:#666666; +font-family:"Courier New",Courier,monospace; +font-style:normal; +padding:0 0 0 15px; +} + +.attention { +color:#993333; +} + +/* open/closed box related styles */ + +.source { + border:1px solid #858789; + display:block; + margin:26px 0; + overflow:visible; +} + +/* OPEN state styles */ +.source .body { + background:#F5F5F5 none repeat scroll right 0; + color:#434546; + padding:7px 15px; +/* white-space:pre-wrap; */ + white-space:normal; +/* word-wrap:break-word; # this prop does not exits*/ +} + +.source .header { + background:#E9EAEC url(images/minus.png) no-repeat scroll 98% center; + color:#3B3D3F; + cursor:pointer; + font-weight:bold; + height:30px; + line-height:30px; + padding:0 15px 0 15px; +} + +/* CLOSED state styles */ +.source .body.collapsed { + display:none; +} + +.source .header.collapsed { + background:#E9EAEC url(images/plus.png) no-repeat scroll 98% center; + padding:0 15px 0 15px; +} + +.body .code { + margin:0; + padding:0; + border:0; + font-family:"Courier New",Courier,monospace; + font-style:normal; +} + +body { + font-family:Arial, Helvetica, sans-serif; + /* color: #494949; */ + font: 12px/170% Verdana; + background-image:url(images/matrix_bg6.jpg); + background-repeat:repeat; +/* background-color: #EAEAEA; */ + line-height: 2em; + min-width: 760px; + max-width: 1100px; + margin:0 auto; +} + + +#banner table { + border-collapse: collapse; + border: none; + padding:0; + margin:0; + line-height:0.5em; + color:white; + text-align:center; + vertical-align:middle; + width: 100%; +} + + +#banner td.bg { + border-collapse: collapse; + background-image:url("images/banner_bg.gif"); + background-repeat: repeat-x; + background-color:transparent; + background-position:inherit; +} + +img.logo { +/* border-top:1px solid #003b62; + border-left:1px solid #003b62; + border-right:none; + border-bottom: none; */ + border:none; + margin:0; + padding:0; + display:inline + float:left; +} -- 1.7.10.2