bplist00_WebSubresources_WebMainResource! !&+05:?DINSX]bglqv{ _WebResourceData_WebResourceMIMEType_WebResourceResponse^WebResourceURLOj/* Copyright (c) 2009, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt version: 2.7.0 */ html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var,optgroup{font-style:inherit;font-weight:inherit;}del,ins{text-decoration:none;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:baseline;}sub{vertical-align:baseline;}legend{color:#000;}input,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;}input,button,textarea,select{*font-size:100%;}body{font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}select,input,button,textarea,button{font:99% arial,helvetica,clean,sans-serif;}table{font-size:inherit;font:100%;}pre,code,kbd,samp,tt{font-family:monospace;*font-size:108%;line-height:100%;}body{text-align:center;}#doc,#doc2,#doc3,#doc4,.yui-t1,.yui-t2,.yui-t3,.yui-t4,.yui-t5,.yui-t6,.yui-t7{margin:auto;text-align:left;width:57.69em;*width:56.25em;}#doc2{width:73.076em;*width:71.25em;}#doc3{margin:auto 10px;width:auto;}#doc4{width:74.923em;*width:73.05em;}.yui-b{position:relative;}.yui-b{_position:static;}#yui-main .yui-b{position:static;}#yui-main,.yui-g .yui-u .yui-g{width:100%;}.yui-t1 #yui-main,.yui-t2 #yui-main,.yui-t3 #yui-main{float:right;margin-left:-25em;}.yui-t4 #yui-main,.yui-t5 #yui-main,.yui-t6 #yui-main{float:left;margin-right:-25em;}.yui-t1 .yui-b{float:left;width:12.30769em;*width:12.00em;}.yui-t1 #yui-main .yui-b{margin-left:13.30769em;*margin-left:13.05em;}.yui-t2 .yui-b{float:left;width:13.8461em;*width:13.50em;}.yui-t2 #yui-main .yui-b{margin-left:14.8461em;*margin-left:14.55em;}.yui-t3 .yui-b{float:left;width:23.0769em;*width:22.50em;}.yui-t3 #yui-main .yui-b{margin-left:24.0769em;*margin-left:23.62em;}.yui-t4 .yui-b{float:right;width:13.8456em;*width:13.50em;}.yui-t4 #yui-main .yui-b{margin-right:14.8456em;*margin-right:14.55em;}.yui-t5 .yui-b{float:right;width:18.4615em;*width:18.00em;}.yui-t5 #yui-main .yui-b{margin-right:19.4615em;*margin-right:19.125em;}.yui-t6 .yui-b{float:right;width:23.0769em;*width:22.50em;}.yui-t6 #yui-main .yui-b{margin-right:24.0769em;*margin-right:23.62em;}.yui-t7 #yui-main .yui-b{display:block;margin:0 0 1em 0;}#yui-main .yui-b{float:none;width:auto;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf,.yui-gc .yui-u,.yui-gd .yui-g,.yui-g .yui-gc .yui-u,.yui-ge .yui-u,.yui-ge .yui-g,.yui-gf .yui-g,.yui-gf .yui-u{float:right;}.yui-g div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first,.yui-ge div.first,.yui-gf div.first,.yui-g .yui-gc div.first,.yui-g .yui-ge div.first,.yui-gc div.first div.first{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf{width:49.1%;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{width:32%;margin-left:1.99%;}.yui-gb .yui-u{*margin-left:1.9%;*width:31.9%;}.yui-gc div.first,.yui-gd .yui-u{width:66%;}.yui-gd div.first{width:32%;}.yui-ge div.first,.yui-gf .yui-u{width:74.2%;}.yui-ge .yui-u,.yui-gf div.first{width:24%;}.yui-g .yui-gb div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first{margin-left:0;}.yui-g .yui-g .yui-u,.yui-gb .yui-g .yui-u,.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u,.yui-ge .yui-g .yui-u,.yui-gf .yui-g .yui-u{width:49%;*width:48.1%;*margin-left:0;}.yui-g .yui-g .yui-u{width:48.1%;}.yui-g .yui-gb div.first,.yui-gb .yui-gb div.first{*margin-right:0;*width:32%;_width:31.7%;}.yui-g .yui-gc div.first,.yui-gd .yui-g{width:66%;}.yui-gb .yui-g div.first{*margin-right:4%;_margin-right:1.3%;}.yui-gb .yui-gc div.first,.yui-gb .yui-gd div.first{*margin-right:0;}.yui-gb .yui-gb .yui-u,.yui-gb .yui-gc .yui-u{*margin-left:1.8%;_margin-left:4%;}.yui-g .yui-gb .yui-u{_margin-left:1.0%;}.yui-gb .yui-gd .yui-u{*width:66%;_width:61.2%;}.yui-gb .yui-gd div.first{*width:31%;_width:29.5%;}.yui-g .yui-gc .yui-u,.yui-gb .yui-gc .yui-u{width:32%;_float:right;margin-right:0;_margin-left:0;}.yui-gb .yui-gc div.first{width:66%;*float:left;*margin-left:0;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf .yui-u{margin:0;}.yui-gb .yui-gb .yui-u{_margin-left:.7%;}.yui-gb .yui-g div.first,.yui-gb .yui-gb div.first{*margin-left:0;}.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u{*width:48.1%;*margin-left:0;}.yui-gb .yui-gd div.first{width:32%;}.yui-g .yui-gd div.first{_width:29.9%;}.yui-ge .yui-g{width:24%;}.yui-gf .yui-g{width:74.2%;}.yui-gb .yui-ge div.yui-u,.yui-gb .yui-gf div.yui-u{float:right;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf div.first{float:left;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf div.first{*width:24%;_width:20%;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf .yui-u{*width:73.5%;_width:65.5%;}.yui-ge div.first .yui-gd .yui-u{width:65%;}.yui-ge div.first .yui-gd div.first{width:32%;}#hd:after,#bd:after,#ft:after,.yui-g:after,.yui-gb:after,.yui-gc:after,.yui-gd:after,.yui-ge:after,.yui-gf:after{content:".";display:block;height:0;clear:both;visibility:hidden;}#hd,#bd,#ft,.yui-g,.yui-gb,.yui-gc,.yui-gd,.yui-ge,.yui-gf{zoom:1;}Xtext/cssO4bplist00z{X$versionX$objectsY$archiverT$top("()0!12TUVWXYZ[\]^_`abcdefghijklmnoptuU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1&'#$%&[NS.relativeWNS.base_Lhttps://cdn.othermedia.com/yui/2.7.0/reset-fonts-grids/reset-fonts-grids.css*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#ADȳ>3456EWNS.keysZNS.objects%789:;<=>?@ABCD FGHIJKLMNOPQRS !"#$VServerZConnectionZKeep-Alive_Content-EncodingTVary\Content-TypeWExpires]Cache-Control]Accept-Ranges_X-Ua-Compatible]Last-ModifiedWX-CacheTDate^Content-LengthVApacheZKeep-Alive_timeout=2, max=100Tgzip_Accept-Encoding,UXtext/css_Fri, 08 Oct 2021 17:18:04 GMT_max-age=315360000Ubytes]IE=EmulateIE7_Fri, 17 Apr 2009 15:12:54 GMT_MISS from cdn.othermedia.com_Tue, 11 Oct 2011 17:18:04 GMTT1511*+qr_NSMutableDictionaryqs/\NSDictionaryj*+vw_NSHTTPURLResponsexy/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiver|}_WebResourceResponse#-27bh8=HQWZ`irt{(0>L^lty 9Xx}~_Lhttps://cdn.othermedia.com/yui/2.7.0/reset-fonts-grids/reset-fonts-grids.cssO[/* Clear floating elements */ .clear {zoom:1;} .clear:after {content:"."; display:block; height:0; width:0; overflow:hidden; clear:both; visibility:hidden;} /* Remove System Outlining for Safari and Firefox */ A:focus, BUTTON, INPUT {outline:none;} /* Fix IE6 Background Flicker */ HTML {_filter: expression(document.execCommand("BackgroundImageCache", false, true));} /* Grid */ #bd, #ft {*margin-right:1px;} /* Fixes yui-gc, yui-gd wrapping in #doc4 */ /* Fix IMG Top Margin */ IMG {display:block;} .oo-inline-download IMG {display:inline;} /* OO Toobar */ .oo-toolbar {font-size:85%!important;}Xtext/cssObplist00noX$versionX$objectsY$archiverT$top""()0!12NOPQRSTUVWXYZ[\]^_`abcdhiU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1 !#$%&[NS.relativeWNS.base_Phttps://www.imperialcollegeunion.org/data/static/site/blocks/default/default.css*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#AD3456BWNS.keysZNS.objects789:;<=>?@A CDEFGHIJKLMVServer]Accept-RangesZConnection\Content-TypeTDate]Last-Modified^Content-Length_Content-EncodingTVaryTEtagZKeep-AliveVApacheUbytesZKeep-AliveXtext/css_Tue, 11 Oct 2011 17:18:04 GMT_Fri, 30 Sep 2011 13:41:44 GMTS418Tgzip_Accept-Encoding_"1730003-25b-4ae28c92df600"_timeout=15, max=100*+ef_NSMutableDictionaryeg/\NSDictionary[*+jk_NSHTTPURLResponselm/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiverpq_WebResourceResponse#-27\b}6;FOUX^gpry!49>IPVaj%(-AEYgy|r_Phttps://www.imperialcollegeunion.org/data/static/site/blocks/default/default.cssO\/* Assistive Text */ .assistive-text {position:absolute; top:0px; left:0px; margin:0px 0px 0px -2000px;} HTML, BODY {background:url('/static/site/graphics/bg-new.png') center top no-repeat; background-color:#004E99; *background-color:#00428f; color:#333;} /* Layout */ #page-holder {margin-top:12px; background:#fff; padding:14px 15px 48px;} .col-i {width:47em; *width:44.8261em;} /* 611px */ .col-h {width:56.7692em; *width:55.3501em;} /* 738px */ .col-g {width:13.3846em; *width:13.05em;}/* 174px */ .col-f {width:13.6923em; *width:13.35em;}/* 178px */ .col-e {width:19.0769em; *width:18.6em;}/* 248px */ .col-d {width:23.4616em; *width:22.8751em;}/* 305px */ .col-c {width:33.3077em; *width:32.4751em;}/* 433px */ .col-b {width:43.077em; *width:42.0001em;}/* 560px */ .col-a {width:48.0769em; *width:46.8751em;}/* 625px */ .col-large {width:57.3846em; *width:55.9501em;}/* 746px */ .col-a, .col-b, .col-c, .col-d, .col-e, .col-f, .col-g, .col-large {overflow:hidden!important; min-height:1px;} .col-space-right {margin-right:1.0769em; *margin-right:1.05em;}/* 14px */ .col-space-left {margin-left:1.0769em; *margin-left:1.05em;}/* 14px */ .home-news .col-e {width:16.6923em; *width:16.275em;} /* 217px */ .left {float:left;} .right {float:right;} .bottom-spacer {margin-bottom:20px;} .layout {float:left; overflow:hidden;} .third-column {width:31.33%; margin:0 1%;}Xtext/cssObplist00noX$versionX$objectsY$archiverT$top""()0!12NOPQRSTUVWXYZ[\]^_`abcdhiU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1 !#$%&[NS.relativeWNS.base_Dhttps://www.imperialcollegeunion.org/data/static/site/css/layout.css*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#ADo3456BWNS.keysZNS.objects789:;<=>?@A CDEFGHIJKLMVServer]Accept-RangesZConnection\Content-TypeTDate]Last-Modified^Content-Length_Content-EncodingTVaryTEtagZKeep-AliveVApacheUbytesZKeep-AliveXtext/css_Tue, 11 Oct 2011 17:18:04 GMT_Fri, 30 Sep 2011 13:41:44 GMTS611Tgzip_Accept-Encoding_"174800a-55c-4ae28c92df600"_timeout=15, max=100*+ef_NSMutableDictionaryeg/\NSDictionary\*+jk_NSHTTPURLResponselm/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiverpq_WebResourceResponse#-27\b}*/:CILR[dfmu(-2=DJU^~ !59M[mpr_Dhttps://www.imperialcollegeunion.org/data/static/site/css/layout.cssOBPNG  IHDRMgAMA7tEXtSoftwareAdobe ImageReadyqe<IDATx} 8LM~UEF.HI:A X_ 7Q9zfB;cD!n q\5#E,{7~#[ DLSD }˖E@!6^oU^nicB @xQ1z9)Oom=àsɲAXAyRS31@#A nq*RLL=ljہ:fq[m!ΚqۉGںiHako|bM'7rÀ1t1dx2qs>G˅NW*8q|5$}:"E2)Mhy11+w&wDT7ZԠ0Z'S!J/unIIIIIIIS\ 'iߦ WηHqƛT $lsq|aK؝Mtai q J k~1ǽB.NXS GJ8ߐąaB cR-2lQQTNJћ2yM2wol ߶iG6[RK倞.۽+l&=Fu86<Jp*))I{tKbk%%M6 ibos_',q>/-٤ցP :׷4 og;^_ppKևd]1l;mҸ58qL|@䨮!h)P5/&KYEor~rgbE[T;ۡ:bfW hيe6X}oåסAV`kr ߐ';?#l0!p`p-=f]gO/GG!W9Avo߁ j_ѥP/31SͻH"rKB )0ŝ \l,Wxm4$ԉ+ =$ W9.fͱr8h,M7g7'p~&|SY8F=s2*A+E=-.hfwX]:7`E͉uah5Jwq-汏[;DkPQ'Arhb$^dlFDQ@p*T.1:pJ{,IF.gNu vXȡٵ 3Қ ٮPf|fN<p'Gnsd5~R]kN7 'mw\ހ ;?V-û2|I3%%%%%%%%klK?UmǠh+bp?'pg_A2 'N2^;^܏)!?'ҧ, * 5l宩YW9v8is;s} ),iE xr>9Ս}'Zj+Jl?F\wGT\ȫ4\ZS!R܏Ԟp;GV{falҊf=5<;<O [e&ű 뤽Hqhۘ>Z?CülM8=E.+VDYA"b#: hiVhf܏`U|Bġt&`rNYVĬ5w܄ KPobmys˛nU^;p#ce)#16}FH IH'oO L)LJ \g5Z} x ÀU`$O0dTUà Uy$JSEqE beKpwxr/Ĉ"a~|.Wz]XlF1So.C@8bvNu=ơlu*7-=1(1As5P["`V 槔/onĒK:0 K¬^QiQMZqEennmEO!;sP2  B9p-hr6qxGy#/Ix򞻫qc r6>ؘiYV(ʲI34v䆜rFVSoҶ=ZQE#xry9dyUƀSh-2t)9׿56*DOY `N7ZD R0FyT ǐ| `1{)8m9Ec~Ffn\X')͹JXySt¿;BĘiSQY8E|94ze V/4'kl@(( | 䠟oWV~imNF&+hi SϾ^bY%wȄMCHrA^IQzcܲ@-!@O ѳ@>@q"t,Y8F(ӿy!qBO^n/Lֱג^0ImvJ:ş'=7!@@hj72Esˏ 82eĜ}@ 8Os.VAS4"oYtK VPW*4u1?aC[^5rPsRhT׳ȸͨ6nvÝwCq_Wer˂~%ɬڡD ?9`R ʟ*tUV Gёt8pCA.Jnɫ%&|w`+?37!9,!ే uT3LMt(ݼi->AG)r}TdҸK_-t m,Dc[ׁoL m40|}מVRALFDZA ft=,ƒ E|_ `ݤOhAZ뱫KUAhI5^B%8*T抵tNpyk{8pj4 Q+>ı?H(/œZ_Z|р"1A*^fm/%ڕ]co/G/f(go N|^}|W`ܺfhN2#Ghɹ<9LX_\j$ M+yOyU:RE|>y\sUܮ+o"W ݄+6.e|VύpXQf<3$%3))))))i}52ͅ '.` 5y5x?O1Eɳ20 neyeK:M^pT ,|bTH#gJWJ&NX̖rHn^G6&>mCSX?V)ajд:Һi.6\U%CE9=?)WOʨ[^.OLoؒ6Ή#8e¢OǩWՉ![cw"Q2A䟆>ezXF}!ͷq->Y;Sv@{K8dϒ1&xPe<ڙ5U:/o %֛ʱD_`L^ )!,a=[maJ'ܟ?,r3E*.= Y8=y0e2)n:^Q;7fFM>cHAS`/%%S{Įҟwnρy.vK^ĥu(3"Be) HԎԉNx%ٌ%=#@ P8f/E}EnO [#Y]*\:SEug ]7(A\=}`cA i:ѡL8ӱ_l"އG l$wΎ;KQhϫKZjjI4rxlX1)3W!STRR@fMWtU< ~Ţ[%>\u?$>2*RxU K$y}tF.etwSJcRRRRRRR[ahn& As/B1Cgp?+ۈ;y݅!pF!^^؁K=Bއg𔷣+~5Y rqrGMA~t}h)jG[TX ;SEA. S*T%R?P :{FT.Rk,VD1ծO&:aőoZt(@g? 10Q][OFUi06h,Uk Ǜ @&pP8|TX=)7y49BϫƷf0T86"jwaV˞;ҝ/Y/]u;x B:} x]燙7R}i*0vñc⧺%=6LmQ׳K Lgw?L u1Fx}=iTQũpНPӖ3V`q VR]#jkN#ȕ߄h 70ˆ)s@|䓤p@Ëkg %%DNl$^1Z,"d k߳Fw1kֆUl?bCa Nй;zW$SQ0m^̢^ cni#lE>-@7YXew 4TO,Kf3y`㪇S:𺭱/~bD_Pvu~Tq9t s z`wEc0@ɽk\_T-j+rDppNB wX3wż܃CC}8T&|d|K}QT-tP3KP5z2I˳7{ԩV/@ u.n? MJZɶb\,;vH$U9c)K >#h!TZ- qH/U- 9yr8YKz Fԕv6Ϊ/ࣜG_y>K۠9}F$8ljU J#o*{D\3rccfDEH+wo`!=鏔 :O &9g&C~h8#(A괘ހfJ11l(r 2usF>*yj%v(Hu%+2:"dgJO鼢Jj*t~dEnql[]P,pIIIIIIO&k noU`4eۋ<ݘP~kIEr :/EA ;NmB"'"Lf#r}]aD)m @ɣjCFGU9~@@֜/~`@A~[9cxj)6f6@{mĀMSPMJdf%xhEs6h XCpP@ }+ڦ\QQ<-J6=bLW]ӑ7fCtONO!ͅx) (1gx0T 0TߑA>NiM|y6PEnk|@`P߰۴cn z{31_<.9EFmnjXmអ_ݺaY_i*!Qx/Hޢ]٪(G%a. XҤWQ_ 颺HY *g+e_# ; Zp ]YCCM)[~PAAjƠ#|vCoPB_AEcE 8"14bҙ8 Ε[j$!{he~<Ĩ:޵Q #+E4wV l^'%%%%%=9 | )O(m"O l;dlĠO2/9‘3ĤuLh c T F(uQ]6!ע)|M CbO#ޅq: _ 92!kxDI_4[q }pا\գ?(3XOÏĘmH=[ BL2*X&7v5t]-k%}GEK: d 9Odwf-Bjˆ??3z ;OaA8ep9={'{AU m3/OW>5":kIJJJJJ 409beۡ^ 9$ 'pNeM1#GRRRRRRR2$v3a0?ٺN<a%v֍ = ]#KT $z뽖$6\zEl\H:Nv` _W]D;!~5cdAеPu1bwfx viݭG/pgp:ɐ k5ؠZ°D #iYc\}NX0t ݱ{2$"!({ ^ @瓔='kӝB2HʎPm A>HcV QL&~.=_UAn"v[*"ABnBE4XO !'3qi{2Sq3b{ œ `}8Q>Eы//Q)}a]Xo3,qicPR%(?腠d`"AĆ(B7 ØFq5, dDU+6ȥC@em Q$j` M6mXljGl0[6F+5]_MU'.,<8](Hnމ{l4ncҲSEkQ"qJ/J3;R=B>\zr'(0u1=63efIixeҩ8ɐЪ6O0ԋ g9q!lS>aؾX27)N ִ&%igV5+X>V)_+nO@djh]. EԙE,a(g໫[lw\n07jiSs^&vJ% kˀ[C`<Ǿ>LmAEa5ٟ"t`ᵎ^gCo^GXH! *H"Z,LK֎ c *ұ[={ )}$uG-KUo6UE~rr| Mf 5ơ]cXaH{.&O4e&A)`] 3ܩbTi7HWE+rqΩ'T*e.v'p+>vtFKCZ%;\@.,õGQӍWKo^c4਴XBr5c8s P|~6٢U-ÒFz=c}~6 咦lE~8GPjL1}wQk;R4xOCT(F`A@{Ƨ*E³*ҢxzoaO*4@z Z0C QXz\oЩ0 qHfb) j0ҳ'lMPjyU?j-< ˮ}}eW5+8B0~F9PěXOEtϱx!ŝPɕh}F-zkq %)))iw% cjr7\n@#!*}\n;|69]h@g=l)TG^%9L? 5,'("~ۉXa;hJmn8Og 2'˛>՚` ZB~M-97؛[ɁwQ;On s$lpV<L IMY.is]ݜHd_js2L W.A ҠGC9=\UnSv5:7%+-`儲/ p =L^-XEkZxo'Ғ#9k gC5bw82jr )k׊2{ })(  QHs|CR[p8,7Kf4*0A ԅ$GJ;bZgYM"?1Z@K_iVEYeK!/ζ+jAj6k ]ez5w̬ЋG{ Xr!9KQ=wonjG> r.C5ZuS`"Vgh&PDcZ)M$*J6VxBQˊlx_xcW>MXw8<9rS2Im<C_a{Vr;X*O(i_1VD Iܚ[c8@lP|3C%FZ:'䘠w nՔ6yg8k/*pڮR8 s"? YRԒC7j\?._g"ĽvwU>3,s8'7$[Mz&c1ßu=p ^]Ԯa6@E-FXAjVİP'tӆuxއ >q} F}TDջ(] ޼ W!)GXJmI.W20.?A:H B"j>K˶Z}iE X|`^*pMHKjTnޥ1>.d"q<XY-=J,j ߆DA Fᰠe@+Hn1#TpVݝ$+by%&|r◊p+zͥ<;GHܕ4Ib/,ӼGfppp&2Pj/i2c꭭{MMͳwNe̺q />Fpw|yQٯ->KP<CX0&"dT-΀&m# <ܘ+7ŕ}]l+I ]B7@p 2,̓쿌:eX]s;.Qm0D:z ܍|e`[zP$6bwTnF)8W0'-AQD?ً ul{8k5qdY ÝڲL1G4cg~J7#`U?X_eœ k?"a%azoR[dcT0[s .]ize7$(ƍwt!sIȎ. dxcer&T9,"Q76zw2k󘼾pWכv/jU2!Oǭhzmr?T߀o$PN:4  ɮ/nn=|- ߥ >b5ZPZ֊ Ӟx[T1^n^^lwFTYwNA ݎ$ԝ8wkC|Bqh>:F`BFwH󹜔& "1URT9rx8=!vrD,c(C=~0# 7)Ӊ6"mh  g?EyNn{"RAhoJ E[pZN,;%[~:Ѓ;2l;V}0r&#X%d*!m`<@"%EG9SC'4h5ҎT۴e7E]Fm$C1z]8r!P.hT įf!ɠl90ͬ'i 0~n]Zs6MDYDS_cCLX\ &/wq&`i{7}` ȁ]st-'z?S1[ammsD<\dpI^oxU zrX>?0sZݛ=}`k( VibEZqH:v6NVfp4ǽF1]氆 {)t$ b  uP5a~K3"45.[BczZkJ41A@%rU &Ewݨ6dS T b>'Ú ;Q׆҃CmkSlҲك-Qvex}<9BŸ}PHŌL~h檘t1cPZ{Hʈoe(|[#iuSmي4]? sÝsȽ9},kI)[i]O.^E,ZIu8Ч04y݌qc,d7wb.ޥL e[a 8K "9@E K@*MWy6us B_Smh!jd' fi)Wc R0sLvCnSZR6)))j 絬LhjY{&)塮&tF(Pfz[=,?*(b0^Vk!M!}> fu$ . uB!qO*cH|z]a UAnߵZQ<"8rli:(|7)ֆeE+&ލ2/fS4* cGF% YzXU#rS@it?&aM'} ;ή?,TaLj`S18T+baê >~])3#3qc(rqY,O ^c7hq@HCqs(?hfp/$\1|rc,3 DbJY= 6꨺;d|w뫩"p͓>``he3b^hm(aKx8'ܒq~.Эo,ƭ[%.زRd,=S($gb]fnzweN~m4_%{jA~}}kOqzFېkʦV޶ԭae7{1M*6;17"뇎z䉃ࢭ^ܞp+\uNC;XɆ~ﲨ'GX+#GWiq4B }[^C{Ο߸ؽ8[@Pw#ّ 4W]x+s7檝tBpX(^ Rs++>}!0cpIWTD(%3썑mk8?oIhKu'FM <> 4TO\)j;~B``m@ؙoیu^{wYТH {8IRpx@$%%%5ʹ\q |[{IC_)6(wN_յ>Ryd$ p$;Nwك?Yw|;ۏ0@z-k|c &cfmFIAހ_&/IkM 2ZF1zzJVlsFٖdO<5<1CFcӊmUcA1zPDjMlu ĀaUQKΤPbL?}%[7invD`?M(=Ź-An7s ^%ͷa nokpi A۠^;bm/h'J6O `V%r"j`oV0wbV 4Q_ޠWR(ZBi֠[kZ~ٹ(qu+>:]$S8{:TXG8X(Ρ@#[ T<ڨYt)lF l QM@9ߟWʮ{[kRYƾ=չ{V^fnhsd)|Oc9Ok_ϤfK{7(YPPZ>(q\* @D[fvWٗ^^P5MQiYSV0}i,,1^seB,c6(n (w] gߤFpT1/!\;MvrqkS/ V޼^?-s{צDi0u.\ رCz+Ƣe"/Fy~Vr<iYå :C87ʇfGW0کc'c<+lclG{)bXRZfuD7moqyŦb%0j08rGbK$@=v6]p0c_ !z۾1r7F80h X6Գtc >>;TW u=B[Շrflj#L`oA 7TU:k-m~qhR :i=d!;*'?_Fb6ucFPo4ACRJ٫L( + DQcbǛy0NNL`!Q C\8aEOh|AP$2x{n4xpAp@8spL}Z p{2wʑ#V^&S;G3I{XxjFbelM"ֈuþ2%@ \ q -6 Ur|*ֆ;bEtJe}X#5Re!L9WeCfEغلIB;T\Rw~5h7,:n" 04z\B[~۸/o4F`q`Fk(fwP4XkO,4 ;v4O%?ҚCyR}-IIIמ9椤q,谚IIzW.{)uyq$%%%%%%Չ I/GmJQAl^T3))NQjdRN&\C.e;2$~# @X'3yP)['de R%ckB5ߟGH=42# @6z1XF25ҫo[ሑ_E}^kȬ!(8U ̼"}5EǂS&U?X  ?Z<;'G%+l4Q2|!g_T.<u}F#Z˔?}~V*ҷ'فtkn@d&+j3}{e*ٲ $oM6(!qojA0B ( !N{b%c3NٽEn<%c"JA:m[8eu!'DeY5xixې*,_@FdËR[1zI"< lKlg YW, V$B˺-`=`RoI WNP?S66a(FqFd_=-Z.KHMBlmCH / 8j]C+'oԵA1X .g bo(Q\d+I Z=N η= x"H|",n\lvY>zBD뗰PkU{0OPwT0+4Q'H4# 2)I6s^LK +V.}/x~b_HK?*ЉѐqP4VFp*;|*|&5< S"(Ө޸pgw#K9nѭF^\J\S%4,yXEzO"3Ps)X^7~ٮ5 #[Ȥt-+IbgBeF CJDha6Z稑E!_ Ϙf IRҨmU?>PpQvuI+yRRR9D%>"'&Le|n.ZVA:#EypoNmDp e:/a)a2C7yo]#4S7_Ѻ(K J8bȐz@\GC$)_zL|PrhTԚ7 *vทHZG+s´!u~.p89aY}1^BD  (`kMl^ms4_?(s}Ht^tW>HUX^m3_9?ƔC[+H5[BO}AC3r{ %B;EAؖ50&](rs:LQH fؒA#ض>G>`\7xM\Aɋ Ow%_rx('kue+%lN))W\ǽ vAzYWn)CJ.SqO`ֺucc+ov0z `.\C.JdxQjabDlII al|1O˝y9M%~dox۸>7w|16G?B3BTKɔ_+?8fRkpxݻBIIIIdPԧ h~pBm8?,Z΃C7ed-RAu]}WȊ bki{aٲB[^1:H}F_D瘏{"$Ne}}^,t I*i\ @l"P OENҸ.BO9kbԨ'љ&eM|ׂ`زv?OV~,֌U@mMm,Q0 o*jӻpVhn}mɟ_P#r)\S[_ctqpyppƳek0.[s٫f } S4-]8d~%V1ػ&Û1 `(8ZB}]i$B FS m ÂBSۡ')$-rVpl;L]=hP@i["[f>]b @=\ao/>tc&A2ZŊ} >][wn@թಒcTDQ{KPy8p^ϪWźfLLh ];n+'||9d7lU34G mJE|Ζ,T" <cvۤQ'qpo1 fty=8I -D.ߧǞS]Idw}<;>TXwxhX #1^qX􊋞gIIIoJ@5%?^:8 G2G^x("uⷊ-L )f6.~|TV0_VZ]_*p mB!7Lhiimw>;?ܫ-}[ܪyJmP,(s /ygɥ!mґR>ATν`O0jP2&6B4?)̦:*욽lb#nӷ+ Qv>n6dbrҤ,֯תJm,$mnGcg`4ߡ*n_%{3z0?nmc>aFaHȻgyǵ{i@|N._RRRҞZuH l%?E6iQ\,[ĐbL Xq[ă{F@k@%'^'#CIH| 4kp P/D!k5RZGEH6W"~JK[ݣ|k-vSy LIFe@+ .\"6<(E(=a?N*X,z[Ef9 $.]9 <ٸؑ2{jݘ2ŊCd@fPj+v]yTtV71W[bd]eQ˅zcBv/G.z%d Rgȡ!;_tHϱy1AEj923I˨ QKJĆbD!'U2mZ\!i,̶N9Tk[1dbљh`KhOY2E>" Lw@\##dz$G=N"֕nTٞvjR,Z[=*1~T~c:A9bkZN۶hS?))))i/̉#!XYѵJ˒BMkPkn u!K0<֣jLSoymK0 }ݬ:_Z,N\+ PyOU1\*2w\*SWP#Ua:1 C 0Dؔ]LwaJ'fG6bL\ /`%~{W, EQ/UX:[G=c$ JAl VD*G;fh!BVIU&%aVT تu, 欠[V䁭)P)! j<2[8Lϊ㼞$?gK!:q}x[')'^SQo2C֖>eݤH ,K+1= (:qGX*x## 8dNPMk40V=[. Gy҃Hxh5<=wC["|*\ߛkz#&$$aH '{h$}^GE7TlT+BIG1?Qlwq*-g~w\e5w?n:ֳk&8x@i񡻉uH4&>:F!/eڄ5\=2^H[Kfܿ%<(R-n1~{3P X"]wyJG\O{;gW&ުtf7SN< Xh+^Pi؏͙夤8j3_Rfap6n=k@0׻f..(9 _[tU^Dr\y0y o$=0wmQ—v5(,hrJ{Acv`d 4?-E NwSs9 1iWc.9 T!Iv4w+;jpm[˔ K>X8(@6JP[%;} T.#Vef0DD[X5.na)`٨酲(\?ٰ6p)Z5J?pen mE |Dɢ؋DTzͩcwF쬷KvdQ͢ENV#ЉגȓOKƖvUR a[a]:`HN}ܛP%wZǡip1$#Bmر3Lb.Kkfk}/kv,KIVDo~B-wcSǨ]ql^k64e*T_]mBC{*% ^5PQ^Y0!¹Bq!:J8dos5ŵmRZiőTιcf;[.,>G|8-΍gzssw^KApOfjU{Id^%&gmV z"/ CtR%K `N=@Y n[ZM1(IdAk nV1фbV\y{RO$;YPGΔ>*? y_uQRN8e;0YNo <ն̲gq)8ͼdtz bc "&,,tq?TA:Ҧh.'P`Ȭ/yv_jIw7~SlGw [J*:,>kn xvGhDȊI ܶP6\7 C>{|򢨢u]Lޤ1⠑vf7쬤 Z"-7um9=?GS]fnUdZoފЯ7u6$ Yb@{­QՎ./H3lADL \%K-SZ'Okl)NŇN%AhzH\vFLX)Rj P<{X87icH] 9?mERzMxCa8VQ W>Dt[8[wZ_[sYv4Vsu؃ߑIIIIIIHᶔ4D Y1KP3hjY˴Ԭ@/aܠeoj ˀxi!f]5Ǐq\4L(`YY1HZYf֓NcVEʠ+ T 0ȶnU5j֔VI9*qGla=ج;B)ZԮEDy H:ͨ6E Aʤ@ԯါ/&4`k H.(:|p[s`]Գ:AwUcs{ *PoRHk&rkSa׮)kmƜ{aFqy>$1ï`-ݍǖюX8rY B/q͒9YU2I*#")SB]?#UI%o/kroQV\eֺ!llCb+8Rb]p^{cmﭸu{J?|d3ޛb5p'>!_l eR(U*c_9 np|SƓnI_=#{mSEgӷ"trAAWx%!&w&T01Zn#þ|z“&n/7P6J!iqZ5f*ûo~i5RЭUT+1Wx& #} N3tcW_VQKhm?=^ CEPoX)˩-,O\i䣛r<'|Cs,Z)?o{W?'y'yP<$l:h!ZFA&B/l(+N]D܍:YC!~{lE&Lmm>vm å#o6Uhm 17)LW>`9 qwVRXrEQYN0:wׂZ2ݩק) ^TN4Tܵ7VTGoX9Bhi:pr1(tlwmt({\TQ]Bna w76M <4Ky<#(^oJ0y#oH7Ψ}yDO ŦB,bml؄O5-4VUeʶ!z^d=Q3+Td:dp^Yqm}/ʜ"xvN-#3KRBi3jB7v_7'ЄLC~P';痵US~$FD ߿x1aBN6X$m<3Pʟe06߾>}%~W~9tZ$]i*ipɂ8`6 $h ,mӜ49zNѴAhxx_V]5],Dw3OpIrbMO'PU }_ 4[؃M;Ÿ 6Td[jF*[o˓EoY(I8>@e_3ZK\ nzXNFa'zmvNgxp(/~W1As]9RDN0RZ&nɼƬ,L('׭4%r|>);'H`ulFθggo?x j% $%%%%݀ t*NἴG/P;apΦ5V4]C;A ǏU[lwAl H*ӆ-J/k<'й| t=Ժ]|"\tE 0]wo{wS% [pVBɐֿR}5ԇTq*EeUB(^PY)I-XFK۷>'WTkEY/AT/MDŽo tnYs'ȴ~T׽c~0YxE=q3V-8h=8W&8KH5Bg q̈́LжgcqY/VXD5;mciFh-U˖c4]3z=*Qk@Nm9/1׹]|\׳eM]a2^#w,b~:*J3|VK.g9oԓۜ'1Ut*Mu_)SZR@ @Vh$l`nBkE&V}Ahhp_[l< _?ދOvE[onT D':FtPoOnycC/szY|(7|H 42/>i98^ '*%t<"]]"_K [ExYQNB/(l5Ÿ屇38&p\ AJAdհ\7lO[\cUSĞɖso t;_{gi~>Dn v=rs%%%%%ݗ23ؒmG?cH TޤDvػ{Q #~+>`]k!|ɿPhLZF+jRGhjC( !%:\@`!$:FT]sl2rbŚ|sR^ ?SCSY{Wj@*/F恭o`bfUu %h̗N6Dlrw0+g "MDTgY.S{rHmގ[iB޲1Qi%:2`9ԷLE<-"yz_c}_o*kAjLuJ &Z|>gTnJ]e;]kh݇ϩ+j#e2b[D|L`6%V:$_Nz ٬ #B;V*R P]3h:Y1Y нY))Uo !Tf֌TZ5,&hk5)-'gM۝ZGL;̇f&lY&iMՎNIϾ%s]Uqϴvq_43rB BZQN?xQVzIju+..yXappii3`bX&qUt9\?Jb׺Id *ݾ~3<≱Ư'I:]&IYyÞNn Wwոp8\,Ix5 PB?CI *b?he$~fI&k шC~ȉڐ<QLF*SCdf/WB#7Qf>㠦i91ɍ1CRE>@m(z: 9#3} tA ofⷂ9K]|()핉b=w+ynA<@>e1||`*Η%*ov٪Me!$-#]GsF U2qhk lI2oc[PxxB~|>j')))))IOO CUR`ɹ* &vkJQ>ꂋsLf2:=ftDkЀ!7y\nY2UT~4j ̜CDz<䤤 } mbf)y1X 1vתv‹W7Bw~Z PC[TGF[zP pC1U?ΟUbU4q/S^{2(UG u5=AֻZ'kmn(5;WU&<^4k2c2l/dѺMbHb*µIQe}`vNYeI?=jv᥆+ֺ,IR]}ETP)Nyi^o!C #D/"='98cE@XHI>@ZYٷUTLbE6⁨āv&}2ۍ 66Ͻ>A8)cS1C*볫 ,7%kV{s1Dxu$~ivz5Sn'}UƬ@Sw#Z;7#K"kP"\cv7a)5Rs K3H[.yQJ[ CvZzh@Һr2G.j̹'i1s:AVPk?RY֙1CSꔠv}Hk̡IJmz%lyV9~$Ş1C1p"dX.(9?$,$Cps1"G/6=&OG1 @}䍻{%M~cЊV׉@ϰ=E,I$#ϔ" s?YOIv68or [P@yo*Lr030Y'<%퍤rB璒ҝ>4ΫmtBԯ:v;НH۷Uvl> >ێL'bQc$ZU)̟TD}1L ߞWjC#s֓>аs!3>>1WRRRRRRGҗeO Y L)'ġ&{<6Tﳮ9f80MzhC]_- waMXjP"U-Hжh2F, P 1"}P`mO7#R*|*&tAx$EmVzoT<$lJ3r6QSo9*t+ށtYJgiRrEo[1?A*Ai 3[!7usC56>+p艢J/@$̈́e/B#̮9`.^_u~ }aюՕuy:{&I6݉Yg=_ )U( @k` 4$@"j ^$lхC1 \dn#Qؓ%Gy`joEQ{ 䳜AWCZ+)IUۍk$E:Gfk*MvLvg{C:pQI [7p ُx?qX,x=D?&,ރ1x}DDh1*jUZ}IshH`?͇؃( őcc8q'ml͉=,5 KQf0|shrSƑ |Rrt{cݟ4*w,Jl`QԐ| "h. .]f!\JZ<0 MJ-4LcPen)3iԡs!-o[!֦`婝;3s|a"R tɱȍ ȥT+x1Q̺o4.WƾC &!QOK_W{ViAiTCUZ|sA Ni gk*9rcǰ ^NÀ' ]%uQfTɜ`^)kK,e2mFftc]4/ZG5e r(6trҝ,Z0&o,7 ^`8a:c2fʰ1\󾢩UD]~zDmd{`|~s6.ӑPBտ>O~16;6F맒s-P=-|H4)q)9kosڡ xnww80@WjH Ja,CDxFwC}Kl%@3H!AA$2O"A=LsDap⮾Ħ-7Th8i,D;E+:sM2m-,=T,(neæIv Ҝ5Y&a Sv\eQxհJ M?r f@4eߢ| qcҝWF{3&i#[4^Lf8zUxskexLr1 -F,+R{-=MޱEA'F);ҙHZP31*2.S'Au`Vcf4[_Nؘ!  <ˌ-i%'ׇdz_;$ }\xg?5S1I> /坝7,ԆqN :0nT,n[c뷛x)+t(krl=T C7>5F͏Sv߭Md}<uџ3&&oE.=nwjc$:T q~oPOV[GP,6"YhSP.<>.Z$G(WtPB`'h1.F2ߢ}҈GMeQwJh榝QSϾJįVu#J\Xl2,6`hl_Avϳjq Ay)641\3>FEr; al+ȽۖQPJ4( N< 'fSV$mp{;3r=eAnoUy#drtY A_cj=Op˷ -_C`S6ܧ~`.ns7YȖ?\$]<禠QlU7RdIrȱ@"Lҗ$F: c]"pRdr[<9%JWɔDNb*S<0KPWҗ?f'9e\5HDc4q'K`UNgS 'Dn; H``xz1$NL)Nonm}.W8Cb_/LujU|vf!336q]v\9uth˪G[07#wpu(QRܡ"Iwv7ll=]G%i Ft sq 8VSoO'&%|(߾pwDI@ވѿCj_Fыȍr\DW{f;r> 73 VZA΀>)P#Z@ZBA]("I}U^?\u!d0jTmi~$^2X $apx:<1ؖȠQMeF2GSe|Wrf"1h fqOm`W+'EF efhࡺg\دwE,/^"-5 Kh^)$_Ԍ-xp0~CGCt_eeD7_$>bsOᄐy'6UԣȮd|/`74=}X%)5Gq%p.9zyƀ͊ycN& f0Bsc;!U'W/c e+UhDLǹWQ! =~= ,ֈP^njh2Xѡ䚓3j7i! )L޶EV/=.-;5j2Fgl3n{f7آ)>Wթ˳u쵾-7q vMj9$w!\!Վ 9TL3bx$"F3tckURrEC|*@ƀ1*g 7@I7ˏ%ҕ,?⟉0cqT8hTiH]O@ ٣@CK;{ŷaty:+;>3]ʫy |GPsϱT}GdvnmA"(g#HD~PfAwZqie)uEu ?Hs\d<8z^<bjZ/dLii M%& QqxCF Ij*QP5uIfԞ ,cԀ6Y;ɟkyH Ӂb)y,+]#1q׭dENO $)?ңZT;nJR)C.COS~lk,:`<_LҔ GM!ŤDwS)tnZg\?NY! .͍TBsDzt+xbacr2WxN ј5D;"|c{1(IPbPUgbL c 'jE-Vj>2E88$ AjS /]\ cFZ/s1?e 宣1ɶf& >$Ew`FXorjþ?uCrC׈$ad br%~?{\&y^ CjoW7>QܜQ")[_?Mxi *nd+SE*lՌZ Y;&=3!z~4z'CW\;l> 1nwG ='}b).<њuZEЕp|ad:Ĉ@*t;~hef|26n, :4eT7^ 'ݛp &>gdP}嬑Z\e ZcLf2H/~^ зBƁ]#f$jDO 4{l"K(TY*DAL36iBk7"fel~ڣPY%`ѐH($ȽP8yVU_Ҽi5 n~Mޡ\ʻL!]r0w՞A3'Ҵ2 p%N9II9f<ǽ+FNpr%sz^LcE{Kc^a2r3>/n:YvWoX`We0flN4f@Cqn kWɧԚ[{痠ȩ IR|E`*F=S,y?ߎ.7cU3YuyT?8rF(3|A?>cywefu Ěоvnw+ڇV"g?CwfCTc>-:d!f&lK™%ψ͍V!w(ߎ$BPd%T7$O((=|V|F(qF.c(:il+@7Zp' L_Fxj )1_̗ݟ,@ u{"yHz tJ(c1)#`s4VK}&a@en@ŅD+AT1_h~  4g' ח{vc}fcP\:l}~gGQf愓q%\[Jqqꫪ5N )I<[)W*[>PuTcFp՞:]A@#"&X8Bڌ7c\3jzZ#r&5զ|N&MMb"=Pzy윭vDQzxJ,-VɄ1p+9d2:<\ĸj0pnVlI{z)S5挓F*!N`Cl|FȎs0uu!FۉsZ" QK8  HgHn!1Ȅ "|&m5 ; (=ukO7ڧ[׶J ˉXs{] Lj&X'_!f 8hPuz~ Ζ*nw^>^hbp|V,Zpbv:^<&ydWd?#IF11+AB€u8]2)bD|9+cBywaw짏Z{#РȦBC3#EOf 'oLU뚰*a f[N 7F79y7t/(Č\BYן HJǎ\y%U$!DZhs^X.jvm7qzoBh3{XpQP7y9Eb'WN'ඎXT@Y &ʗȑuDT;[‘C! ь-=C$ۥNk,؄S̾iP66RR!R~f0 YzJj/wJW7bV $ } mf|p+W0 RJcA5(3_V5oo͖xP wsMKJ.g]")O7쟜^^(: I,"ir2(h'nwݦljUò(TЍ|9DYF/,T\ =B fX7JE`&0+Bd4 3E(:2, )+k<.>fdE"ۦJ;j;'`X:Q=4Dy1+ңk*B;cGkI-n85.r(%Uo *𣈋 tIƁY jrbF[}WptC1gcp4RP j ;+n0t|OAtofA*A0ߗ%{6 nj! t*UoŌQ}B> N`ߐ8y_˄Cnr[ MyTbB>Yi>zZm!##|h?cA{-NKfvC=ٮn3hg{6h+niCS}սv9aB}`YX!26XaRznۣY"c"Ş[A3, +H0<\^ (1Z ^#8dKma`!xtɇ)iw͒|F_ظ_M\;|a)"0@gX!. XB)mo eRڍ"E%4f%_u$lJeϯߑh,IC4y](į,C^nhqY@Q:La!poXgA -U]ZGICZb_M^oT+-EXn_ёqmT6"B%adRX`Y^nʘbUihSȾQ2?þa$rsI3)%se>/NE9MóaA0Ho -? ;K.z\D)ZhW0Ulu JڨeSe? S蜶oYlIVJ΋3l ٻ|Zb|-ImQk9{ALymDdzKcЧSfq /67u꠳w4yܳ|5 1)묤Yy xhne鮫9U4KcςfHD\r{(sA\icN B6VŶ Yf ~X5/EJVgE%cbR:0QH(oay²R35mTq^vQeamlsri`0&0[˅\L!`к\ +8VS8)ÖL)?:!Nj w`nzOX/F_Dhx#nĸg$1C$<0yw{VZ8{uE?S(q3Cr ixb֓m-6+=Һ0J725Jy^xXڋٹqN? $d]` t1 Jt\HѬvn G~.4QuN`YW"\H..pph/.= iA#:LHnD)PΣ(1ԫpΆy>;-[ϖNYԌLs_y_guNC)>#Tm|jKH :Us G<6hz~܉ﯛ2(g1O[ثj|gvmhpiQ *Dn\>yѠ~z'tkcoVh}"1e D` 1CRt B*K}Y-W}#Ap/U΀IvRQNPQffkؤ, ſ6XT{`aV }z^u;|]WDS#_UApBMdU7㡧g0-wZ@Wr&/'~<Q:,]>T߲-B`OeO”՞hJI!nn:ɓLۍF9zxH?R_gT V300ryutE?1f I'e MsDL CI!R9*Qt^K1 oꈗ̢ю!, H%;{ &FHS ʫ~EùجGQ3:dk@PCW|Wt4#$XdD+J)Df62}xhs\,z$&\Qn`< M'Tܤc<~zHO9PBgz՝ ETXRxH,< fU(s i`QvDEp|qA.PLRg%AG\ 깶CH`BKi~f0SүY!è*Fԍ+\4tyAȆI5`'n!rG=J. à#*v@x zr_9@CFby0\%T M'EGȡ6}V(]!ϰ)<&*}Ҽzyc"v (6pgMUP95Ύx 2n!ǩU iզP5i"Z׃YK DŽ αCWQŮ_ƯQY-C^8/%^aٸnw#ނ;ŧ3euKGt] joh%YGVj5.X4bil(S`'P,4x4ኗyvAQ`=DmrȡÚR:q[Qv9nm۵5?s:9]9!5ת07vof*t-{rA/ 9<[u]}uO3{o8QH{U5AAsWEe\309]D5=*Ԗ=+_D1g0fK8%>~,hVBm<8=aDd մ2%W3w]G?~T,=mFBm-q[? hO*XhtTx*z5FYc'x=lR֪$FmFGJ*ݕ ⷞլ#"\Hu˙4g|(Y IE µ[7~GG>o /"d9r Oh:rv3=j6luW e}Eoz $[.7 ǖb'sW|I NxntRZrйIĉz.p)ܯTSmpOsv0Fsj}%I_ݾ:}^B=t|YןC^S߷Issˡ*ȰU3`U!bq}p-W_GOZd+eּɭDLK,Jagݚ{>/!|BU? OhgS<>K[B7MHXEt:]lr3xԈ+#DpÛ)f/뒲X i@zM4p8Pj[zΝ}\5'Tbg6NQ]{+T&Vlh{;G ѯ$Fp_)쁰c7|$DHsw,uX%{&Gj#z1^~D9V)G%!WU 1==xҩ ӎ2oW-./"/NΙu0SWv`ٸב r(gzyNZsȁȡ Q7F݈hSVǏ`]jJCGFn[h5cF h g!~0X'VNEp ;[_r~ʻ&t}1mV9W.5TUpnw/kMkڭU7u,2Vy#̅e8,Bqx̊} (Ix̺b7E牛Lmf k^T5BcU7 TeI ҐMnQI3OJ0umMN4XP[ܥ0'Y?acS:/e!~ ^A +ba( Gతa@sVNgl#1nqjQNV'{ ڃ@2N#4b>^F7䍦Woe<4˸(؇!z&{~nMM%~-:DK}#[Jhc`ӷ1݂q;@a94ʵG~mO$QeC a0T6y1ԃqe3J-?5x$JF6q! <{,GhO_8r =vCO4C$ k[iޚ$IjsvcAa0v/j+hm""q"=Mf$~@"+ { \H)#թumETqT-4 Rl=s6Cyn@qGN9ei!8r͋=8s!ͣ/c4J 0RٰDZ\#MdwbDjd~?Y%; Ree7y!FdOw^KM2 V[.nH]F-Kݍ9c4Y*3nwvH[E25PWp9awc8\Dfjpn۴FvǑFźz V)<`JP^eCU˾,c6h3רBCX5DxlK,!XAo]!Ƒ֎F3투#4#m:Z 3r\j^iotǕIV\wKq9${u.~Ыnuˍ?vnl#GNe?{x6ܘU cm?ݪPgXsA:rub9mQYLGNFCb!~ZJ~e-ڙat|@3y(x&$s;E,9JUϧGc..q1Je06x7FBFng@C K?n g,DA:v9_뫚Q!~nV5oC]QRut4Sϣ(ܟ|&=0 GLCackǃ:Z:A3~+K_p+2խķѨbPl?:/h[i=0{jsb"5 ]EwDO]P]8q A"ja>_Cl#+9x"Q!SG @%Zpd,9Ot8x X+` Fm Ng'>M3-)_P]2["rYjBW:z"XR:A)ny'SNY4(5Dac? ks؃..( h=؃4/ٞdU(Bh,y,,qXv|;$bX,*vth ZwD4aWYP0{ܮZ2ɀ@p󕇧w蟷-µ;c^I?Obm]KE!f:l'{ھuW6ҬRV3"Յ8X8?dJ#e鬑dM YÔK(\{5`ՅC H(y8qdw zU-S3%~̪+)i띚o)]w|.'Թ2j8vCFOR{R{ ]pni G˝Ǻڃ HX/D tz?h`XPUy6!_ l݇U āPPNֶ$kA9W~IG?8@'\+9<1-ah"ݥЈ.gUd )vMQx5]A;H8s36D@]%-q<'Ae<|-rnwv u"m)9\5ZUK$30c[xp ZI6Hʰk~8Z +]M}"xegᦥp(Ϸo>qh ۬ 7MvWK'Kb,Mdg֭ɉd`9&'YLR#8Z7f(F^%,-H@%&U2-q\>m2@7<Ȧ6(v֏w1$C䦻Ǣ$ZnjžJ<5s2zr& ̙3ڪ$t`F r^#A'iF(t:5\Zt-r:ulB9+P֨1Oڷk!,')xDXx"tws/lEuiOp,bz]ʊuPӔ_ -EFf57:N=h4fZJÍYMKQg>Q8`/dk@HmPn MSڐ8Ϻ cN}l(rCя5|e=}: My으Rf^rpOM٦>\ 0ˉ-RMqr ˮ3)lA{0=`0GtLzwMһnw{*hhg^TG,7jl3!>akƥ Y7Q:lkKEfTT&Cժ"st`)yN= W>sL,S_Gg'ao3*c'usļh6o}}Ttw[NU i_rT=/1(cI P4"A|uut͌%e6EGZ)V- 0{CC=(Eh8 ܉%"HB,HSx>İ4@߬c/80XmjV}衩vJJWƬDl*Wm1Ȩ~PFI0u&|GV|p-<`\cmP3ׯ{EnsdS/q3UWn{`5-QՃQuˈ@jWKWVWj+۹w~1'e3 $ӭeBD=f#sPҪ%g8wAJ/K ySC^y=d~$YKWa㘏pxg RS0yX>_g]fA$Eq⛟`8nE=yَXwcLf^ɜ+[2xb!c=Z3A*V G!9HUSs&j Ĕ@`LkQ 0 dߝ6!gv}4vW}whm{>F6hC ͫss&xosnwޡ}d[sBPCH: z');ECρ˨`(*aFM0m#^=:nQW$"F,#[s:A1R]'i7Ҽl,43tc JCIE:rZ I Q-I̼7o KgWF΀Yc|)qпc_*nn]%i4WS|͌4,s iDɞPOXuKǐ i|D?,!Ե,,~Ta'-&sty48eμvk^r9:x/{QK00f(vnwLIpyNp:=]ƪ5-1^Ef1hRʎD*b֧/'Cx1q\]y2mKm/a{ѯ.wos2{/=}vnw^t,1B7o Aޑ Zg2T#)ꎇ68[5 #%} 40t`^&'±X;2vߡz[15LAiuL$J'0WpkC&*υ.QiSV$1]bVj\nw%V飊ӄS L1vLuD壛!#d]5!5;7 wl1*2JvIР۱Txk@t S.5CLMR@G KIaOm5ܺdi(E-Ԑ[Кȗ;"`__)a)"|Eb,TQpĬ3T?;H?-N {|~04R(d"fv0ТK?;Oz)&jV]PC{ȇ:u?&]yb%LXKqO!yzA8Fs T"s90i/^X/n*'AN24 àH]W⠩qnqu.*TޚoOOHs-< 6FJa +#>%/,cxO`gBhΪE7ϙ&k)R# }]YO45S6sr@Gm VG*H}Wz[~)0/?Pw Cojty;,K/ 5RrܝhU @u!01o_A;ȇ_LvX2YWQT sȽP@pZz4 \fxܠ5oo,M] aB;" ="w.Q&'1>j[߭de^SpEBZ?AHM<X+Wl]NqU7Dlj \kAϱvХ=W8LIH[->Z =V_ ydZp##Nkuy*ʖp`뷷FԍwQZO1#|fqY GLI620C?nFdfEK9%&u&v[}L$z{5&W'c ɋ ͵xb6<Ǝx踭X__z[WD[_ >CaѼLdMae H7%FGLCWI"% t;ͧsEWxbb㏜EfnO ֹ0ΙI].i.ȵÄ#up3]V̢&{'󷷬gah(M?#LAl/ExeT t`.ȔB&ˍlՊXCE1"1aNkv~>eU=+$Zlf:amhKS,YkEJ>5-H|=q׈=# R}T%&nw݆}uQy\oY9FHDdeĝ5jzH303J~ zJxQ, [$s]_fs"qѐz3\&G edm4w]˯Eï<|Ѝ̈́Cx; /ڣ6hr#'6)1TSp{vU7^WdFTSXfٗqƢ/b36WTJ]:U!nw݆dx%|zu0hgU\k&&c,YX%^,^cSuj )Ԇ%j @G)Uj2X6 ƋH_;Ē38 >*Y%fe&K}cݡ6#*O4hKĸr(LͭDI:zíJډ+qSzqtWau]! hU~m-tQ(ǫˌ].JƬSHPLN 5Ĩ<ۥg.3-m+ETÝFQxF1Q},o0"άh-"^'ڭ]_a(qSdo8NogzXDZpj q;f "vo n> RKT«}?2BhK.".U9򅛹{OY׆s(_3붟''?&kj|Q#bI#Ds wvmD\yk?`gنædiN):RDHK3y ۼy-DԦ&fl-5d-4u0 GO%%#M@4!jhԤk,l;W @ڬb@F]k k*CN:efڂ>;lYi)"dX)$Ąk5^PqfFK7Muj'?/_Ei3O)]֎NΣ&E8aqsoK~jwn$6ϦEGd8b6my[duO6/n-ab}B?Z_YS* XJv; >2OG¾}#)\`9T.ц^Ht [[}]40D{,f  !sڿ(~ondW'fF.@Mʙ dClm~#:4!3J6blIN$P:_8Yl'f܇l8Г}Ljdd1$GA{΃h{2q%Fd$JUSoMՔ qCnɯE(Gy,ͽ֭uŏ}&(1&Lb9l6cyaS sÖ1b+!Wp &~Ǵ>㓇fvz8>ǎy%<'R+,kwe.tBMrtbL#/; :vTqe 2Xi/`۫4n|;Zz ٷ 4-c\ ^DyO1t]d]by9qt>ZS>D%Ua29R[־+ 06DUvA2 ڠ^(jSfKK}hVPΨ4޷93&[Q!'ǸY_YNQi7 7s_J'xi"nv.a㕣ŻaTx_UQ^UtK4Ɖ'hՃ[}HꯏC2k8M9.~!掎0l'pCXl(&QrtԻkШ5B[BFUJH7ڼ=X*@a#s~1n"xEϝ%|U q%?嶕=H]jcRow0\ܗ3 enwv vT;,cda -}6Z_X 4MspIu-;l 3Jo=PAP*8>)Z󼼯 BC wp~)k.f#ق D\.YP=J* ̶Z6MD6&Uyo(O=MlgsH0Fslzդ.Afh!㱐M `{c 73P&q6=*Fsc [ijl|}taL8p^}qJDnT^᧜|XT] 7BzL|KEҡ2 }%ZF^wو C&(O¾vyg:~\4CUfS#`h{]VfRѫ3~˾hbj w1_e#D+s,G"^A:e<b\KԖ11s7#ֲgr{vU&AE7&T D>8 '8^mXD7#^h a >K{\YF RE_5w+OCV nz;qw8=2:J" I vk(o'C>@,$HIB%D N$!"/W+B{!E1P6Ft?|W?v@I nyc|GBb{p'ˣιՆ_>Ӿraa.^(.,"ip'%e/7/]zĴw)V5Z:oUðn=WH1n:8~mQ@ \zNkvwh>[=}>pLX1#("ʹm-S <. 2О/DlQրJI!o3E}p֎ ;kDG+xEY,Ww>c?Ls[?X ak=cV5=Q36\-,:<P4|myX.KU-s-z< G)09_CkYlK]&/F0}NLdS5X0I6o 7$bcTZ"VY%~yb$S:Ѡ.[*<+`%JJo8;7,ʣ-q :Z?el49ԉ䲌᪪(*WvxѢ԰vq?6߸63OEL0z'xׄE`B0֛D\^AbV>ɣňxgǮbGq.8-LVU3б}B0!~x"EW)P}\pҔ>BV1,]X@H 6ʼjaVj^fDK)!roTo!WԻp7h;쮲xd h h3L^rlY χUC_HQ/qC_9 t9w WRbTnw;}[`|ԠUjN~tO(rm6A894qnkWbDߦ|bz;Dm:m,g3 ߎ뤤Kg1|:5KG=vp각ԙgcd7BCQj NYն QHt~e+ >x/vAsTv&O;eҞDM\*MZw<k)=펱*AXv ._^#nwZ+m թf-f|0gP2sY ǍJ./4M3B=PŽ1 p53*O]sZ#S-~E ʤ@5 ξV[mXKKnmۂVnK8fCbۇǸiU)t4&Ybۿ=O͓RܽtqFcjA QhQ37Pjv6}p.:1FXPspZA:&97~%bl~9}<-3mDAW:I0"́a_\,{(8tMҫd>3ZPٯno.GMOH|ϫ{"->'#y0O{`+R uaA[;^Z0׬$Rj1j*k<[{#YB"WGϹu8ǵr9tƕ*tPDC͹pcnAxA0uLtDA9(>Q Y I,ZǥOWf%"()a/l -VkcUm67U<]/?i6i@M;WWtZYۺM!x[~4D.@< j5[rЀpbF]VPB0'Y̨~)-K- ^.k=W9pk=?#]/W 6xKΰk詥}[bD%ަu)ڎa8"Ԕ3yNYXxD ?T!tlx/Bs;i5~ OE<&,ɻl4\rl2X|M-\6*q?Rۆ[ P7/!Z3[qPGF@ظ}RNCY%q\ZV9Y%K-cf'2}وr_Y|zn4\gAVz5VYn%CfcoԢ*F_o!!iOQw,W{Z3,f}u^+:LE<η֦9)\292_BM!HZ}^YuiLoSms@DK0"#Xސ*X]ReiXΝO.^)־JlIovi5_3#Ny,%K_OXjnqtssu-w^DPѷ[%SjoYg((BZK?naD3NU)/ჩ]q/r4kV!.HkS@Q!qX g/=#wv6Α3k9soZ4rV@mGlZ{=8sd# p; `fD?ffDb j=;^u]l0O7$V> Wvjŷm:y4OIz3΁JWLtc 7خ0bYW0/lG\~o%`H`_d⊇'YVVx* eQ `G՗P=BfX7b](C{@)91|(UҘ#uA:XU )`yY[rG۵ɽp,2[!kӁPǥkrc0Oo[YA-5?gHޡ9vim]Y7@4ssNs<;bCu -Fz$9y_;MC k~a-Ħ$MX]hRjMu{-DD aDّhmzEzkH(&LYЁA슶:xNFN\^K<6?Xg<f=q0"Llp[qCN t0pv 1BU C@ݮj<[IzN So[nwVk)GDhU`>GsfLHސr@I&<#ev8,:r$HMVy{^D=yrzۛՋ DF>A e|)UUʘ`/MU>f5 Ъm H R1jB=*wg)KY!\CQByX?Ng9\9v#X-ʙ^VeSҧqU٥ H,0 bW0ʼ2%R"OB@Gczzs3ɫ"kPhmdF|HB۪|#Oʿ&J3m­\}9AzRT(+zJTMx"Hk+/9mOJYWz辥'`),p99aJsvQTgWg=X\_4E[38$`o닅Gxo|(VtXyت=L٫p @K{Tj)u]~8 ԰=7=$Mcw3ޠdGPhlq[Z#@ Tb vgv+ ;Ms^ld(gt/O5ѫbgY(`kc%ÐO'1a+9"S y1}+;nw݆6ϑCKOGOQϮqe|ҏ 50#jfz)2 g '°@Q_ H(TlݍT:g5˖?)2$RF,e)Vqxtػ]=347rkP{k Pl$} e*ҁ b8)QI)X1,rCXC\L&dhB ltn<:` O{ rF#<|T-CKrܶqQ+AGIIo['ܥV|H0J/T?Ibg3]U$-1t-<*2 $e@O|=@g׶Y,#F6=p~I/u5|~h,O9>Q4%Z. cBw#Otw7]@8 ̝sˮld|u}rWļV-+VĻq5qaʉ zQoSivà(qP&j*`=E!Rb=RxeX".6T'k^]7[\{ {}.K!eg)[2馆c˽i{4rQOxB:&8bYP7i3b.qnw^>ao]wQ7O[NSx")7V ڼwݲnw޼}4*V(Px|ܳ7d9$g'`*Љ6Α+a/RbS|ֹۀSzҫPȑj}~[+6M$_3> im\vNUb#*}P!j/ƀ85o#xe;9g`zSmc(燽Fx =B=Ƣ+re|,'msġ+Zxyqq1Bumvv~iA}RƒLK򭭞aꡒZNK$.tj8 mtϕVJo/xuc][TiR2ML 7?%>1,2nm1XU^ZJ5>Yz5 r#W'E(!֑1Y_L2Uu 稴^9 IoH\ėiKϭEB$/D5/5N` `(2kVs(e1 &:6y4,˗&D#{CTxxBۄߟrN>=$3}S0nݰN|,'+Aӎ70\"0eBWZ z*K }*1tpo7MtA#l-Xv@[qaf 3)A2=Z\ʌEfW΍HO!DG ?,Z8${{-"cfJg(9U^y!UwH]]`oHSP5uO z< z\IQF&f=>d 1[e'm;Zۻrt- ][%F2jm0Pac7mp{mL[}'U4K ILK)4I6Ai1~bhҊn";>Y=]QzI=~;ݻ)FbS-8s*w݈CϦq.>̢GM~)e#lE]rNxuO wՄ#93dvbB4%*s AX~ev!|O/ ՌR%E:EtwƐ,ߗRdfCo1d9= :g# ޕRfH| ĝ\n.Qqٲ7} K(C1 .DB,CJ]zB;&Lz׍Z}K|&k5ȇdxOZNJzud_X3w[ł?wc|!ł9=2$Q$4Xq&Y Va^z*oS9WL}#WF 8 ‚]ZRB BIDUyūfӖ#K:&kdPL:lF,KEEp[tCl[0M:CnVk##0T@ 띉|qȏNBFSlI@.Jd^ D09 )~,1;!8Þ:1: ΎHFEZrukBSy%)Ļ8@/,?U -se2rx8R%Ő72"E4Sp(K.o%z:qWv{^֦䟽ZQb&sbЊDmmUPF?KYLnX%JQV?H~qq#jbN͌RpѠ䂓ӌn_pၽ"96Mopnw7d`͕my s`l{Z[ s"1jDr䞋ס"g֐8տ'bf!(+,i7 4*0~HyģBu] XAwiŭgXs}C!/gv,'\+ S5Ǹhv+TT&iNSIzB) vJ}QsG3%fMjz>*mQI5֤{ @-/^̑HTՔX5YݶDLSN ̚ WoWvhm V*t(-$Ψq1>Fl Œd@<ǹl+O+$q[AA-hք$q9]~J¨vd63CX=0~:/E3P%14y X7S=E .>/N c#wwtͪrɂ_#Z>,+:ZQ7,p)ci {þbܜ3uJpw"N MI 3sh\P!PL&fԘ،/* 5Y;~@baVJXEmivKl"{b[Ū7qi(.yP0W_%}s'*.cRKd}ժ^8ld؆͜Kf`G{tGGYz ]X=;c4?ߊx,J.$3J $<0ւ9c`^D?zm gI]b kDxyuE) yM %!13 "h֖M"*:Ka61 NE۫h؏^ڷjiw^bdGQʗ MیUchq Aѩ-^Ǻ c !_`*Mы7k+ WXG@rYRb.ܽ"woW3-߽enw[G9ۺ51uUpۗ+O齑X7AYT\T7;lL6lqIIpIOyB եb'c2bB}b\I6Ҝ݉5-"u@mw2u¯P=S6ov҉#,Ѹe{nWj#h-UջiKW~u]I_S}d0Pmru{v,Q$H kwGo۱Pz\@lU˓H]"FEZ0uVWyL^&&..f<X a=s͏-CY?М7qh]9L4Mx< TMtQZ }wK@I-K=v+OfVHJ~ptsX6}wM QveXɛM"ܻ,d 36P(sn4Q]V7ft5IYu=ĊHkH=`h$?pMT?a]etY~6[&ވ#I"ûX,-iVK#s2'G"5aE s.8szwR|xh O,p9J0_G [{_+ 7WY0pqT0<ηDwu0A`yw IwW l6lY?ۋ[{$Yy\w89 b-33nj}Zl uY{ ʤf`k(=vNn=v^*>\``mfоۆu(|PY~u1?^̲4Fb0Q,0uΑDZ. ,ԯ>iճK쪰Dvۡ EEII+~/|ͪHC֥2ƩIl]G#x󨼲sEZ O:Y1Q8N68U H-8]2N:":S9e;b Bހ E˪P QyϴeZ*N^R kBB2lh&JPmby dCV8)yc7"R+Şe3OI<.c~q+=Ħk*Q_z|øӌA%pfm>N_6A ,4}8t ̓ZR2Xӂ46 k5RȪa-qhyrL˚aQ_2Ojې܃DE$R/+kGRCG3Rn(-ׄs&&3Z홧X2B1bSA!DWu~@`. E': ,!$2` #FgQY$  =4ҙm]Qb_F/;aTNZdE+:Q y p-^R:PƌA =uwcN- G` D|dǮwpX_I*폁e8:uԆEYǹ >kY԰!(pjla_`xItW$}2ho,-c6YXM F) ->rA:R衐=TjG! '#d}\ЋѢ'8 :X{w?i&3/kF^?k ΊXuvoY16wp..#`tTxi? jM<ēiU[n*]"&A eFӚ}-*9D/teMM'uDqvW:Y 8 U^Qzb 1@NYSFk."Oߞvmْڬ:lU+#08_؟_.=Y*xn796{O3 ҫ-(vJ`XzO]u8`5qϱY{u7fmak3|gTp0K?*8Zo aE@Bui敂e>\ >Lw{;FՀڃeA*#a),8l?B̖茼XgPgtCJ! 3ůbOz:SYAE1ҰިQ V2o ),:a{ec*(!["a()t@OdTA! z{QvVnĂE[I~70ҮFy@jfvGU۵n[11}MFh+ȵρ`'_W,_dx[ `;T'+yJybvWv٭^!OQA{}/V.}8T\FU\*ob)Nb}˟ Ti#qp0ȴ:IPKng6WX "Si7Ta`Y1 #)fW$ nt\ĥ(852XXvUEZ]@JHRA\Km"* ~6H*#M"d[ UWx~1(سSItA}pTto:mcQ>Tʺ93CoTq.忏?sQگ2ڞGJ7U98i4ȾOӮ8g:\~km? /.AzFxKZa-R_= vDy$AR%3 *Yr$kSi* ;? `o㈊:eH h>3<ðyS[ ӻ q (ܐni򾷢h) ߸1JVtQ.RPQ: A/7bn X#7hۏnqƨD /w) BW ;MMQ":iZ4֒Q#S1lxKqG uj ^00PXm''<:͒Rw8 Jt;WPzp;gςG#! c>MDC/ݥH<sBAf#]\gaHkM>0+ꗂ}LJ{yn5MO&0/ $9R2tBHJ_Py|ƺ̛γvF5!v5:a䜳O'_3j1/đt@95c蒑WOgmfr]{xgO+t" ~y`~v7fՃassuN:2Snyr"߂Y_3y?+)( xxWfmA\]KzQedVv)yV%N6NA:-zaMA-q ]؁4`W{e [a\\YYiب/,RUiyc fC+( #B Xdؑѿ(hJ$ O1 +&Y^F1:>Ŀ*ە`OE(Tkꦤm"Bp"VuH#Jas 8?<...z5C09(%bփ ԼW"zuQgME痂!ދ?Y6EۦYr X2^wgϩ hjѮLQÝ@g0 e,#qϬ(p Q".9 voqium/ i_-5 SDEezɽS+(^i|0#ͣmN#$BilJf-K F @Ί\"DZ|U}45 Ӛ^q!@N+\Zݷew3 xM{7]7. 5!I; B*0%SMdոEubc|jma`Lj2rb%T%wx`$: U<|EV߸'AIܒG ۡ/S!O1kw |WEqlOw"uXKU[BO5Vґ6cǯv)eSM͂࠽&l_Y*;)^j6'A!BuP{ =6Yne{ujQP:YB9+#0̔ᘼq;Wɾ Oɶt'>5r.lxTM ƼJ/AlwZaV@`qW Um(Ep٩'bgYӲ!Yu3=D,m%|yDFQsjɘ^`y2x=y|xyG«}w|GLV\) [fo =6lv8ఙԢ0)/=i=d5zfT6=/) y^bPɐQOy^&uTFVR!"-Y Kb# +;*J@.ds{` :F^TzO kǍTx*tR<1gmXu[0],m!ll8.XAc%ݶ{L:v7GC?R8VɁdZs,*n: ȏTy}-3+ۍ?mC3y0MJ[MAulS. 4(@>.6kuU@{|B:2)OJƌ {VgIZ%.'`4xڍnҡ; $90I62yAkQ2>_56~ -9A$b<3fJ0k6v~RHj=B͐Mxlf U/7/k]XyOva_&%iv/>bh4yC$C#s\,,uU0jVݻ2u[Bg{Wn} mu82df{0lAlig<02I;?++8D;_}VNJ6l6[\,>ɼ1":M71LjD:p-x#KsϚ-6l=q$`űnz/#iH(C#T#j̵osf5X+\\v x򈉤GF wa~Ġutvc> QSh9[j:К k#s`#>@M0dn<{o|{L T5o?79ma1XϖJ٥ $tl9tD{\!8] ~\-V=Ӕ,KMM!WܤY4fh)̱]ŧi1`?JmʡN=] PYPw1Iw0o4C*_/y+u ޹{ 7[̬$»!cjv#r=wvCf*+{dU ׫@u9 ao^aΡ:|82j듾`M;KӜ@9m_]ڷ| kC^EҊ\)]`l}iՂQ2d/$?\L/v)ԉQCٽYw|ؠ3:h-n=59EW9l|z,H3PӖ%@H6FƊ ŇT1}ĕvQ9hQDל9u @Rs[9p%ϧx&EygБ5j[NXBQBh"Ζ~롊,;,fZdY]%#Xϴ@&1u-߷ڻ+XMa:w=B[-ǠYYX^QVj)( Uҧ5hjf`-CeWߖ5A^X1ƾc!^\zș";JGt|OTMIt Cj}‹3FZ^x筆tm_Wn@QDdp %S8/aߋ^XEQ{|Q: w!뮇+l:s.W $^m0D2vm{PŐ~kTx)EDl\ݝu"wqdA?$|q'p[52[x)cɊ~Mi>OԄ~ Sce$[}1\XDPp=Y- Uq^_1壐@خ=wmw9X0,aIuV %R&duw7,l W,uϊL9sf%6 0YlTͬLH*\mhVcCiG ʅh F2+ Olm V9ttUA͚Pp@/3'EHh#P1 pI tf}+V+[13+w8j=K\&l5\FHc.,1}eF>GfOr)Ct2Wm`;bҋUd+H:|z-+6Y_[TpWݗA! !Y(c[(7{ 'R. Jib E@TRHj ӢE6}@W&~L1Mk[ =SMtQVRnw+o~Jb-LH};%T}:b/DFC\%]~[Wb0K &lA*[,U,ð:8-3VA&EG=,µ & (غA8W 9·*).EM>{"!@O/B3"Kk!^eHr~6Hϗ+E!\cQ-  'ÿ-VE-G7}x6O?qɻi_cPnخߢ\]:}#njOb9olLyz#ǫ@mγ'l%rfֆI섷 zl8mw` ijߺ=«~k,eޏPQR=bۘmYIlӾ$\{yYP+$S(9T$ӨV/3"Jm)2(ǍE x9_zGCUFPgoe"د}VR+LDl'@!vj(mo r^Q֧FL=j(.ktvĶ Fm8{FZ0"G:CO0J}  .$^Lm,&*l_L:Tg%h%WdI2%awNSe$ }r䢬YOⰝiTwgl^u]`D\-%I,d +kt˗AF4_ŚQȼa }Tvv3^Z^An$O?ir9P~5eoL;smd-}m%M;^Ç%/ j}؂ˮ}v"OZ?\8IŰ;z9ЎƥD-8IQRFTvމ)=ɂ:?8&&Eϟ|"-Q'$C2ܦCj"[$KNi>%d\SVNxZ 5Bn1T}^1n$eeY\nBT\'mTZ3 A/4䑠+>5y̰_mt^ҰV5+.s lZZxNO]ivXW0գ>aIÛeCq#]`܁9ffK?Ź;Dtʬ=i%Ӂ6$1QEG @~Vku Dނh0 R|t$ш>jNnTɾ `6Կ"wWo|׺ fY_%˻^m_UX~uL+8si_-Miw֯蛎{ 1O؃^p䂒yly8t4\>6BSK'OF厤.8/d =[p #Oh'(͝Eܽp5q&lf{{K͟'Oq[!Odnݯƶ~2lى (BW4#_yX&f+јwЋЇ'?cWy [zy7 6۾}%"CJD7ǢAH[lLM#p,.AiJ DsV4GjEo3<mw BTBY䱔zC [6)*2[ LrJIgM=~>Wp {q)\Dj%4tk$6w1}>H0Bϧm ⽶jRnʰ){^PV5]%?ɲ #~+|܅'aGKdkyww:y vՃ)`,Os.;UM蓮]Y89HغlLQ&FSSf3aDEP[1j}nQȓm,^:J,%Q@{iee6u͛x W&(-)! 8;q=m:xD5"kREvk$VɨPn1hk+:Wha ^|XY .<8{qN t~S}I(FHDx$M.gMߤOfutdjwbY!;Dv]^PȼУj7[Eetg F|1/6_uZvg$34*bB:]=Fdr(G$M4Z` 5ܡK~9 VM5paӤ$(K@ƘF=2r!=WIS~ k\6$(&R#nv=2\ ?lM>Og챗?&z%+9u櫱r7^?Si~iדS{܄8"S.Lq^T_46$rmW2r{0yY?2Acr ZEH,X2!Ȣps7_e hJ}7s͚󍜒A:ZE,a]QqٮuEE ~qڳ@}*OA4ى/;[\=GKwT% Gtf*{zS3Z71l8P[VRX {Koos lGdXrǢ>tS!dͫq+.QOB?;՜FcϸnR5aS x7Y; )q!+ϊM!uWiX!Hw; I`$:"],MǸ@Q+}$+fX"z̎9UelxڗP[['ƆcI'6Hy|&¥0té3|`2 Jt^X,ABLIۂnÝsa&ƯF's~D$^|y=~h'u=V#n1.|(h>l gj:%(a61N!\X!PNx㡖p-ߧ[KZ%it㋈!݌m,E7OٙN>ĽQGQ1@f~:M8 Y b` (LI]EMT/<¨C-:lwZGR`B2w*l"#;10e +J^VƎb{n;B# \Kzu]8yY6ԆjrSkHS# ߆+% 9B7,~㧚ڵSLJm\xoFI `k%1+Nbɜڠ`)3͓\n}hX rlB,[ J}W lJ <T:b$˶Yc[ 3}hkgc=k=xyWը[6)4ץ3.Zl@\IIJub'-Z}/JBeKIPO?5¶4hlp)p#kcE7YgJB@lJx5LdQv\ {&uw1K4yb3rPwBޒo O1;ʝ91gt >SfmOnŝ S 5!~f%F٦Pv&LCgm5ۻ {}&J\lV 1,/Qp*/BN|-Pru$ahE?,jmsW\7W!,\!u.zwHNKZ`pSէ&ȹ=mܖؠWE\zlܸT.n]s¶\* F[%ⓔgDZ4BwrձĻZz!Xb@"_!J;#|?o} /|24fa֕㰽Z${Q S6Rw9ǦOز!wtdM#nu"hmhx#< 4pI@NqQzFs!A]x jl?aNgP\X:vhZb E fFxO+8x #L& z:kZg2]J*ڀwn5 K͜$ѶE'Řl;48Q ,iKYJ] 07fHMp1DQB'}_| ۘ!""6fhHn-Y&pixꕵ$g*5x@ԀaJݺokM{ŽՁ2YjC1;tճ+>N~R^S}ۗ[kw{kmk{Ji5v{G4.k^%6"tQ`R9=&.&D=L,\*t*XBN<`G2o0U^W9k^U{ѡ=C8Q&JFomïՊڠVqz"1$o7 EER'"U63SL7A Kh?#9CC砥42j@ϧ4ƨ^[u= HpvHW!:yo/o-pPy ɯd,@=DŰ, 4-d4p[WWZHHۇF6 m|WۅBپz |: TW48r-j(u\) 41ɲQKIWXvW^[1Sv"J/gD&Rkx6J]0p~kI3Xɳ`XhE Ds5 @ ]*ȋk}W! U `GkqAKtL7S.Q5Ykq!q(r}l>J%^1#dLE9cK-'3q㮢R] -hsf *X3{K"qU !< X_0жzfeD8Ҭ~k5ط5 0Еem-h!XE!/tp 5[0eq^b;^e7Y01JEAXCGYJgtB]bb(gNƤ} ̡ cX]V>h{3uʗɎdIKKƣeobfXufg6=}W&w9T MpNFL c0&j4 ,E!g/H-qF13[wrlxM~15zuMS Ghu=ߎ?d .]Cno+E }ξxݸ,N~9*'=.WR7M.##N"Yg۶S9!͏P)ܭv_Y1$0)dP=Y NOxE3`IY`V?/_['|5tbR[k:rR'x=ȆP_`qh#n>*L0o3\iyBqb9rՁu#>dn[}'+HO#Uk#Fi[ ޝWM{)E#:I* ||GGh;lh!XqMR_G<HYl78H(da>*҄]ei@0 i{*pIF@WY$]<8"~ W0#+β62ñ[bQv=EwojjnE!ˡ"L싳޹ayLmQBL?B8CrrKjwHYly::k{TL[ŧe7Pp,Z">coX IVcO!/.uui;m%n3}ǡ.?b;kַn$j,Ǯ'hO/b!3/:b`=- N7-}9< hK~l+wJʹZUqeLlNzb'>^.6C7|"pq6lj& oQx5kg s!>3wKe2l6loݾ>kJ״UlLo6B|60^DMm3l[O0}v_qf$Ƥ*)8c +'Vᱚ밖C8'"qNpi3պ;Bll_9cz!|[h~P+CTs",QL4@ڤ$Wl"?.)mҘQc~7Mk~>^D$8$:^CKP։`X$ϥoZA9J0kոWy8I8Ƈ [.CQ]ֺ.~, K-~.24f OAf`YY巰1{-AneL  ս,ô&]1[P/?OW._"p^@ӴHNQ-̎nyI퐵`<ʰ 8ؾ"I33[P_`p{Ѥ 3iu8Aaׇ …Ax`(LjNA\JzT,CaϿPW '\pS gϋ&;q^yW COx(ΊeYxDki6uulsy2iξ29kn;؟9R`Zo􃜇wݦdM5WcN;иM!K#Ӹ`Ώ5 f G84Ŗ)F#li\pa+y8CL~2!x rc`֥?ib*&.a\"\/v~jv^.{/5*ؗ-o|kֆD;S0Ɠ@ۙ)h qARpP!^jv OTQ6#[A,v۝?0; q7oÆ!Yd^ U$NUy#av63}U{d7& aБ= =q8 ܂*r,viYy %4^'䧻I!U6:ٳ@0YS5CI23>X80X?<(Zpu ~i?cV|x{oޡgYUŞ=:"œ$RoD!^Y`vphĬqi._'M7r1-Kt~DQ$mgݡҦק8fk]]gvՂ?VBcc1dP*&'N7i5=m6QAQ]Vܜ1ӂq.إM@t&zs*CMʉGP5Ua}U׍/*^+(xA#/R`Ml/ ܜٶ#WPW_yOI 'P&>BlƑ"7l$L#l0lOjs}>W?!Of;-@*Ji65ɴ<'c($(eb.Sw Dxc=>^Ծ[^χ3L5ݝK; IaZ'eX[5a[M$!?fCC);*M6q^N͊ i{F3S W,DCʤ,rG?jĪR4Ndzjj*6%)?YoFAP+ jpQ[؈GGgRhZbRW 7>1+cez?LqR q1yZwL+s{ 1|f+~*\i<F,#r¡!(TAK؃Cd!Z섮eZI,@"C~pʥc 2|UVKaQyԴC x-+4mIm\Q{'i9uW'{Յz'M8/ȚD ^?m~*i]u(?}",ż4TKS$-мʶ;.K!q3|x\#$}K4ML9CZdS- Apk P G Q wNۺ^_qN0$7KĒF!aanܛzQ zɽhZ]rjf*9p)(Ioҍ|WmPQuƥq|n{lc{ܘGsOsJ~b.;1lϻmEٖʑ$ԙ-gWW W𝖾KavWxWԖmgFVh  `=_uF,󇾚u3Z?:[^t+E\|L5i[{y1y SHKZ/;7Y\+Z:;R'$1bVV됑ѶǀOh@.hd#|%rzrw)81~Ya_֕$!i޺9D,I7q'_\B=q+ð|uO^%z*|.ĝxm"Cki_$kƉQr;}`E[wH ɰK?ۗnYi~ES[wDct"49 =P}:z|tǣ.&tpeh;HًHn\Jc$O6v ,S꓈vT;X4ŔYR׎CG`hiH[A j$͞|7A$5w/9%Q71؁'7p4c47hg:t7rT}FJ^XF!7X]ojIUx;nEy7y*vW 1$XaoqMhb|mי}\C 趶;U'F3O:N(9^X#ϬB?ɦRSsAt%+ix'`Rx,a`LWYPa< bq*xfQn$vI*(e\1hZtngA79WW_&z젗AjP_aFSFR`]9,Cְ~HM'@^]}xTr m)zrP^@a6] O, T4Κ$b@8or>s\66Xg+%$L?M#// i/ra5cRw rv׌C&NLDZRu\@gL D:]nkܢ`"vH,P5:WoeYItmWsbwx1snMlo{ /Edס tJ9%,x[Y̠"|Sx(KRw۷393S:AG4Lb< .|=h$gPh=Cw)}Ś }8AgA:1Ie$b~@8C`ei\}l06Ar#rV}B>u]Rn3HѦf'܉cg{U%wCۛ$īGlմf4wTAMid(쮠:L h pRrLS97I -c6E 0@,xGdm(@lWi)`tUb+5-^۟@>6=<EH1gEV_6i(̅Fv{=ӶJ*茓oa(\_^ Sa c[(IeQAH_@F$,x(eZIMc݄ᙅv,c`@X`z)ozɴ+kiR" ludZD,t|`?fh̨_&q1rH4'rLv^\Fts͔6˜>б'>>pJ .䷎QǃC`Ip>TQ:c}`EX徝^7 X''z78DJc >d.}-| ӓ8_{ƽ *\pD`۹;@P2-"PveH {pYcA ojt_ıMD>o6g,ezܯsWDi>@[JΨ>tpFE0Duj5a^⒩%i1vzFK٬Q}vUY B\xC ax+>L jY ڞokݡY< Z~Z}(FEBlKp(R&7ŴATiCրN`kQ…{7]UP%3.@FLrtD< nSTD43 ~LkmM{q<`'ʵN_vgE~m71U:` I_ٓ Ւ642G"a3)PSkaK9B=op{ӵ*kʷ\wz}0sr2PB&qs^?0WdžF 2iM6 x#rIzV%^*d;&+$K{5lC4r0oLK:ã ͝)9m/+wa.?qo v{Qn?RyTCa2 '"+|Ikc%Qkd.QJSyK-!jЫ۽PN .Ӓ`L+|zA@-vNr?հs{˥9p2dzߞ0׸qw7؛tjYLvٍȌ°ωӰBbX&idVWH lAK= x4m;xSV~FF)&vrK8#}?Ԃ)_1-G_.ܻfH[>|tD0f^_yWjYx0%/)טs"B14PX&fD|-d slr*XUa/\OX]D%7p M;hcVM %ăQI!sISOHC/.q*/5!"s4l2kbCq,hRfXnHZrES@Vp> {UTF#pan8*^}1̸xC·ʘJ78ъ9ڞ>A?\>ZԭcޕXkд?8(.b~7gpY)a}-eQO%e 0|< Or6TAw6rQf0nkOO&[w=gm>M^-|[M/;7kM.,3}6lX"yLmF?oʾޘnfm<nO%+gC@VQe)h^kvzFlXS!LJle8Y{4˺iHEd QWY'Dx?(h66>ˊ2rL8(|,ׅMG`SƠu +u@iRq4R8+AXchxzJk %b::31@+=I'fZGhz\dԕ-:#jt0Xj}^Uh&^mh D`Cc!JEZ oo Bzy[NUcpэWl6l]bH_U>6a$#l]dbX/G)b}H{|djx ;ȁ\O+ˀ;0zjhG4 b/iD+q|ӢМ̼ w.{hdI)ʑҽ#d)\z8ڑ,"c,ϡ>ꈻ1S.]^Xң7vc)ZKSҼEp@V##PIM -';(X<Dߓ mEqpHM^,6ŵ.B%sՋZTų:^^\;H ULG"$FuA+_!lO*}7Lĕ-MQ2-od?NM7ޡWCeŖ]s$p]y6RYƘ H^h+#YЄ%lgeK6>oPqZcp^>c?Vɽ{r ~--/+ރzp\ڇ07X7#Ȥl6l6'iFpޙa޿80v6B0pVmٲl7k ' /aÞF:7[PSb#[l.OONj`lvO}>=;5<{2a8Jy&2 %܆I^z_ ~j q##B6|3H\:ۛblnOB>ѕ)} }]!%J\*eAlsg$q c-7h.v9);1`g!6,{iR ej1t@NAf ѻ*ō]&jO]Jq0}V9< X7!clK: u /*A~+<\L, ;5tƐ,n`/,fu{j|lc[ -ӭn146g2}ٽ x>V%Ë%U)YQ oZT~#wAsw77 T靺m>G{>g'h~`&*ޥhsh'|%Ot°I)ZUڍLy .Oc yEc.WT:z23Qj^1 Fp !C+4 5x,d_ T_,tTXQ]m\=)t86BL?0=06DZ49MrGexhkap)~O` OIBOgfah;k_ sMJZ&q┎(7)tR0:acrFj!2kAp3I 䅶|x`d!:D,~~Dsz# (i[ut_;{B3mŔn3O@ mǒFBG,j Șm@r$Z+rGu.,ĐqP?"8H z0,8&.֊Mnsy;NÃsH c7U@oԝZbPC8,diH1 ضRzs+8#:Yp a헀j\$5P|u{,IWOڊ0gP-FόIkB Dʯ{0. !C|}͡ : vpOv cIâX._VVAzbdWr;2 2m׎4*FnyGo vX>a=3ؗ\gbӽyE 6lMU9EOw836oC9d?s?Ѭ8;\&4ۗWk78~ M& } i=/.Yryp ))0,%'豛2D5&> :oMH $ KX4q}IU9bΏAܾ`:Γi4:CܒpUax0[*9Ig!Ҵ#"#U=#&۞%Fc4ث:oq)YZ%-W_ -mBuW~z^7 [d8RZ4Yۊ4#J>|1s}#f`BTϯԹO•(\u%ᅇN5%YP:"a$zX`͸㡝uyT@!_nET 4~Jwrz]\]*s~}YљQmPAEYA!~X`GPaye 5U.|AEaaYAJI XIQq4u"FaRXt {sչyxz6ٻ9o6~%h^'nY'N7C(g ^6I}٦;Mk_j 8 dK/8K W5uwGÍ%uTģD]`LeJbT}1ޫ* Yh6Jbroʶ2ry.25e>e3HyB |2_뿛c-kb+gDKql95yE62bakNA~(N@V)*JSʘ!mJn_R i;oyJ"]ŒҰ6 jU-ޠ3j=^d4M8n'#ԕVC0d\ax:fOVOj/'qrTKNIy^4r 9lZ**'Ԣ[^<3ڽwx.߃*w`pݒ_wDR,;5n%2=m2%+v7ĎH!ɭ<0ч^Q[bMϒ,W.6ĆzQfwhB+%El68ŘQ%&#\vPH=u7}z,F:"ÇDΆs*@E]FoQ쪹Q8AKkYkd TG㓆4z6+[m.tZk/+;Ǩl{OMFi.L`ZQB×_wf0UMn4fmo"\e:R%ONe? 8<>M;;1O mf}m?bM | cK\qe?b]eKld>eI$ Ƚö o^c:?X ]KftR Q'p 2`(٧)E 4,l}3C+c oFEc.# >Cԍ7LvP]}'g t]B>tl~Đ3|GwްĔ4SQIu9@| 'Ak rt&'$$$w0aoT?sO$!!!!INHHHzUs\9q R _ruT;d~ra<"jniѐ"kS˔̴2e}Q8szZd<|-9dpg΂BLdDُ~8@9*F, ԯ`}_ 1 vhAYpc춭ee0~`G+ŦxʹZLP ą%H-T15}h,[6m~;&AEw]hVRXVrHf?oJȭ$R*%Ps*GIU<֦X~vo%$eг {ZogsvdsJso7]o>!6G-w+lLz${<ӨOoD n ћNOIg8WHqVÄ_#cf!Kb*S ͼR9ЊvY5Qz4Ѫc>s*ף\}"y{SBeZ\ҚD% #:vh܂j&fI)bG-IJgb7.5& FpVኚrJXXSc%v4YDZzQ9  ŞtvQrZ/lohB'siCHv6gg{ fp YgyK '?aC3~n{ZS\~L^mw*mY>n"4e7X6/!H H%!1H10'lٖ'y#.~iv~S9؇æa09v,j5cMx'Z*E*B glVX§rn~;m|q)P3+KUBY.lG@a|1?KWbx)q46\fȫǗ`nMkVɃ/{z{4o?yU pv8UNʻ<_/m=#n{)sH7tUklzDpJ7pГSK@ 9hG'}qǁrsǾ]yZ|ǑJ^իFaIHc0{9_:8[з"Z7i)WD],#[;h]~"fbvIHHHHHHHr8EvL8.)WLrl*'IH!r$}*` AmOƞ8q:M\SiJ+7ji5 AeD5ɻaĘT, ffag (=}]7x*QϾZ np:$MWmgT6n~14xw-n ٩<3em=&hT-Vn8:^ 05WCzurh$TI9R}RcRkgZR9p͗+͏!+  5wlOډ]fR)A9Xd(v5iċ j !LФIx@I6Cex,AV=a9uZ]G)| WCv ݢF(ICR6JICPf=٬Z[M`xC-D f ĪSܚ홅CV<(WؖaF%40:4fY) ]:+ImTz$s6OP~,&63Vߤ;!>dESqI./]DUhʼk:\X릶VLN23!pabkvn|yi(|e6bX;+jD8b yVNOH5b<ukw9:jUySsld&1hB)WbTkV:WuAf onT-Sq&&g)%6ҪIHY#Mt\G9]`js)yqq j|'PsGHHopTςDAB2vy֘BBTWR^\oG-9pZ į rKHHHHrgxs\-#Jٺ!fSH u/,><תI V1(o;Wb&g%'E+hj`yy2}v6kE :))dzVJYòxCp3+^~K7d3҄j~TF g5' C&Z+8{ݏRGybbz.,_ƶ.UwDR:\~n"V@~qF2YjrODp`2ZyN93O4{P?jk~MN#2R,1Ù fdz9oXZ N2t/8y⏆F&zۢgDnXi>,^[[8wTW-KXQGI J9e9龃8AVrSg^Ų(=uLjZ " GI4Sخ!#'1-f^TP=`wP(\W 51L"1 DG9U\ (! 2#Pڞ5TkC gLfaXRD Kbb o(&P0!h@v[!lz1f¸jni#}C;4r*l{.W_y fW?t8~k'xmưUyG*g'iObuv9ĀK͊jVP OuJHbEEucӆH'83պ5křswf)#l$j7uv|%ER.+)uJxsrWL|RBB7ti`$$$y3DuB0 1 )S u]ƮU B' gfװxF:VHw1W7s=:V ̧!z+ 1J G5֝;Ԋ_i)e!vyJ={sz O.uͦ6:wr AUnPVLH4؉_ ðd-lQW6JkTa) k K;"Ȫ>D1MPV3{pTNt5"ܮf$X(BWr .5, m 0.ðb3hP];`Z%P}TNc[:ߠۋdv'bMq&KRwnBPyǛ4N4jQ}̊hV|ugޫcsHg}¬Ro7H/6i84ZdEoJh`u@jljߖ+2ZB%i*$8%FԘa+ ҾphqcBG|z FS65r>'9`m'$]dSf>q- 6H=%2L=ı~dH(H¿`d4 v۟0ܲ91w-Z(*ڔ<5Vޝ4R: /,PD- [k,?^Q<!M? ˊ04fþ`':f5PߕZS":>vccUۣhAaE38IFX)H]^M3]faz ov->3 XŜJbq?L'$$$!fhD槮1*!!!!!!!!̈́^V )3jV#\~gގVWl (xf{}⽪SIFW7f,uJ2=I"19jׅnmaE'bDe8Mx3@5[:W>:\4M<Ъnc>r"8滭Zhv+}DL +E+aV̮E\P# u#zx$EŒc [&V=( Éc6ی`TTn_-) :*BrQ)6df@ǹ1 HbQ̡-+jܳ\d |\ll_uϒUQIV; _3Y0!!!!!!!!!!|^rVȎ)%ՒKHHHj:ET>ܖ@Fٔ8EX(5*/#%Ȉf̈́6~7$vDB29u͸aB- A/O󤬔 Ǟb AZ8e> x0q 5Y]%CHT՛-**=4*T%,=Dɷ(Vs3QȜ VȶO߬ K.F̲m!rdyi|Wmއ M@W7nk5Ex&Ŭ(ԩWP>*nh~$x2WL)2/R+U'{܎L+' /]NO?`K4洋`OʉQ4 ]]V*߂'1.q%XlPШ R? i# zOeB2%-.BCzVGNqS:(!݃˖ LHHY;dbJd,pR) mJYBApIHHHh՘'Op'({D/ o "L(?X'NĤ`B)8C5}৲{H4:ޅE_wiͲdA4",nZA6[Qm!Q{%Dy&\o;4op49nn세f6plijܝ" -O+.zȢAo0Q3 5oy ԙ#4 N Gm0UUcpI`ͿveZi-Q[T!z(42l@CGKP;݈UN3L~|h)M_kFvID%=tpO-mA<(1QYg1,!F/Ba.eʪ),ն( ?ֹ#yhb&^ d՛&woʛX׮u!yl3烪{]Oq#IHϺs~/+bwFi?[jӋL&MR RQ Xvy'T(bZGgD֖}D`Lh`T&"pZVEE(G.! |l\<,}mYXascY#UXzNP 1Zu%4~%8}'?f!t.mJe~O'x3INL9?XxR'«NQ-zL vj(qD50Sz9YGIIL=VJhI:;[U],˽!G}.8"kdnTle ? PG{sOyKo6z䎅hN٬MY@16'1d/stWEO'A '0| E#hA[ӞolNlLjZj{CA~|f2ݪ}'o;Yu2Q89rPGmiMksaS\ |t²3ESQ2e) FPmMVBQk9_qRQ7j 0Cu[bs1M2$lcccJ",STĄؑ#(8Eχe Vn:!#A4eI\d;Kv<ؚϕo ff CPNM(\6I˄-eVbfhy@*i >}6 vqi V_!E0<Og:0\P7}6 d0n5QM TFKsTS/R:ASz<49:^X-ġДhϯ[h1ǗFm`~Wve ѨF{$kDuRb4PWt])Ի.Y4%Sr_(:UAHl7lITZe cN9;J2l|\ѝTm)}l QGpVM u!40h5H8:i<QtS_B>2kRc; aH*`K<4UɣfQGeMluZXܠT!Kw?w#Q?z@ -? ,vgG%'ae# \+n]?Eeyۯ-6zXTW89?Y=Iб'J*ZSm!o鑎}FxBy*hZNV˓KMnW]MeS<Ơڦ0(tr %]L+ 6.ӎg4 %e fׯ09wX#*+ZPe,8uBkm+PNQKL5/9#󉪬A6.Fů]Ґ3N[ 9UB/?4|>3#Gx͇ES?pJDu,^1W^4~hEK .؟BqàXl'vq MЮsʠĩ7<Dyn"b`tquN'A[( 0: # p7iRm=`T~[(J ߥypcbމst3'uFM;30v<#cڣ v?m,MhcSy{dq. D8py6`ydAFkގC8>RN>GX#A)e+崾haia*=svڏck39z!VGVZpRN@BB—o0%$$$|#.k2}Ʉ4R'\"'MkzY{5D$&$& ~GzBBS$؊k}4CeDuE0 *-`K۴4!~Q+h{ZpQ6'$pq ,%\̋k_l8wꂤ`Mf ]}W-֯ொvtC9<,imӯ^bwӢZ[ cq Lr`T:u + W?d*--Z5ed* jh/KM-'me4!8YNdv9Ë=4zZF,j, NwYU@&e-R?V1ܩgi^d؊K$]) 7o[UFGkN$nx΂ơ5:!KDXpfD)w՚& )OEH , ؆TyZ;tI^< >g"/x186H}axpaxgi ϲo3x9!!!!!!!! ?M+s}3lSgqPY+,/=+C5g cUN1 tÆZ"r'2V$`4Iqbb$eX)yHgb/hLup7}xnhs,-4[`ϗ/HyFAC / ݤyi4sMbQa!*].E蚚&g7=oR*z3|1&Nn6oHpriQ8f(;[@ڻdg|X]IQEM>yh;bɈPez,F~9U%Gdڭ줊RG2;{愞$ ޝ|чzl%OUFI뿢} oۺi @ SW,4#ԇOhN| ovWM1Yc-u26+{74ɑYV<Ǘ: c*Pr.VN`ȧ=nA((A.m _k e r!),%l*c e"WeAt,^I`*g&ėxn7f[kr,[^Dʊ.@(0 [,^( ?8y[{1mt,HY o#4ڇch [1Y;4>foߒzbBNh>šagD`2ӝDΞA:֏Ǻ{[3e._yj;WꆕڭZWYލX@C[r#IvY`/00팏i|/&͉3טHOHH ތoeE)LM|wO{`kZ37s%JKul`(loL%bupnǟd([DB@.n$]5kTQ 5NkEzo!G}9ۜm^?MS&V}%5z٢\-IXNjȊ/=*3};kJۤ8g)7uE8}ZM㏗$;u31B%\hڥ~h=&ʯǣaQ:+\̚35UR!lNKnƖs]XžQ$QT@}b;PƖ6Pv%P+1}[7Me)0den\w9b| @%djQm. ln<6(^~2L23rJSSq9=p2N1: ~IHlpl A,_?׵<<7+J`?l+HARd*3o^0+d˟dA;k~i>iDYewK7MJ껓[緑f].0VЫhzр*Ն> fFHW4^89522[X<~,G (!kdʖӣ~ A jrOC"Y8A>)fʪWd`mZc`Y8lBR2jJby3f]j/{[^&Gr+xB人=ڽ듞_)\2JNKBBBBBBBBBB2*N&U _ #'!ȏ>WS 3 > f^MAP6Vl»Ϟ7б:S g%3>jat zeʋo`;`Z;cQkvd)QlË!SZ"*E #)0C9澘IŌ )3|OIZL} Ag/C'CPm2Mj_8 NADfN.jR3AK=+:}X(+<[# ;#6b1Mيg6[sqUŹb/`f[/0ʺF cVau}q]q֏_ƈ1l] B̹(ڍwtQ ݨ0$CyH_t0#{ۼ*ա1!VM@>i29f<#AhQfsnӨYUCxήx[6\R.ϩ L~|o;?,ۧ;HM/no$w'Jhqh/UȏT>1ڬp(]r ӿgp\ xxhXfHI4TPMR4+az`?7ˋE)+qK\R$jߛqh.VY{lp6wNuh홧3CRٴ#vVsUGRKm !>c:PސH )-7-c.MM2]xո6Z* =4(:2c̪VG,6m]ew֌vl̼  񨺄 ?VAP% ;:PM/LwjJ Dq>*j@T-e?4uKhUrE7NdR<Ѡ?9nP!{eC5pt1(V^|f mFW X9ET24b"ۇ U,~)<e YB|*e nHy/@G1L{x-+*yDchANFcTft)<3Wcv=|@0ꅕeAt8P24`g9[4#mݙReF%vxf#91aA G_w2&0SA%V3-!ڭ !gP6e6 KTOgH-GyQUA/7R77KYSΦ9ɥXE@k%wɔKSaxi9XedEWNs9{j2uAvQ0bÊZ$AR=3cBQRQ7(*%VQ[Y]K#tnY&!z_F2UBBBBBB[YY.@1qDIHHH9J0-Hd5EL' 3 ?zz ~.JJ8@M]ls*߃~2ɸL(:UƷ8juYߥVj+Sڗ,DfCVgLB{5%?5.wRI\b>.ڽϹ= 0ܭbkl,\8RCPKXT#Yx2fw!Zz9ph] _ex̧sC *Xc{45h_4/2E@Qka-N#%Kke&5[,L'^Zt07RɑcC>C&D ۋ6ôL f!VtW^=#!i Fs XQ©R'l}mT+T~Aj?2nfÐÖZe͟^;[-H!hc0 l8>&U:B5_)K<'U ]OAj:uG!,O2)D '٩JyfXFh1͋Bdqm90\!=>^ ]Ht%T*fݿ99d^5sAa  GFkdoo Wf ր"h(Iκs o񀓿CЬ}:F64 !t 6׏p>ftmPoJ=^3V%2/ rD~\R9Ypk9)V +a(9M9|ޕ:(&#ުۦBV -?ܒF#PfAO5n"8D 56Z8cylQ`wS 28O0Ȕρqww{e5nW10CCKPG4 {JZC(c_ TpT.g>ғ[%y}g? $9:@uGuiWN`LuVuǎʜu$h;lX ;Gޢާe|)[~gT  zG:4Fzb`)",/OIFPtZh ;@z 'bcm?WIp+j(MsT+Ś15UBܶ{BB|BBBBBBwA"gw U]hi-xHU{/^%eo>RWA^_bE)@hL=$#}%^Y% ' GӆC{aQ3 \ tӐG8 xHtpR-;H2@4')- ^XLl~'w37F' Db+ۑ*@=$~VG~hM8E`TuşAT-i_G{ZZ{҆uXYiw13x?T|h(_UÑ˭3,vnm̚[+`!+h{z+N4eTYK:z30qy+%8; Or |@HˬO~͉uc%`᠋D0 $:}F2,pKh,N=|s𙅰 u z;؞9ΡZ[` K,\ՆWw[9UM‰đRzc#.[0*%Oz_ivU"Q`h_K' 6,$Y :y2cV ܪeX"A#0A'(fnanaZ4EyLaj}K4pTVam8.?N=gO 4Ψ4jf%/cƳ:H2BeAȶQe eW$dPʷ@/ՉB$*NuNkjiS)nu> s}{Dl@h%{BXZŋ:4ϫI:6$,eN,#H0uyo>Hܖ[@pօZ rȃa6H]v^Y9d G2SQ("i1YqU[9!Z}p=scC9!IZLkOozjb($5mIH84 '8B%9ϡ[S_}\43(!VP/.47 rS@ex-*x͛<86eLQ)vwXԖڣ"^O鰊1[_U o .1=T^Qx ")'O'ާun4kZ~ ' 53ذɁH-]"V1C>Hnc8K֠8JUPښ67^TJtL3 lre}t&wFzn\:S\:4ﴖ!(I)9>u_bl{op,ŁVF݌z\=us4=)8fR]\=,DDL8P)7O^Fm]ʆm=ܩ Gr(H~v6{ĉ1K[&]_Ҩ=WD9lHĈ@;Cs )8 h;$GZ_O$v } TUאfa_{Z@1v1ӈove7ܒIz"cûprӳjƅyz!P6a:ֽZuV2I*?1|S4i 2gQJx1E,ɹQ AYEkD AZJ.oւ\1dHJ5۹M\v^q1 V7~ Ƹ&Nܝ-K%&T=4xD$G7 pb8uIWhujt[;mѡ. t l?g_8WA#VWe: 6-^lto|/ɾ-uH6LDK ;]S;kk+}IYav~.v|W1g(qDʿ~hg.Hr^~R<$BR -*jGlE8PBk Ӆ&j?G^/OKNHHHHHHHH4ዣ߆?@~SV ;0j*OQ2Į귤piY}YVqV/F*.3E d{+ZdxƐR gA%f倿.wX)t.ϟ9S0Sx,PC7# 7]uf Aκl=__yuڟ {ZےD7 tR >nWqu{6'^u)Jkk RzٞKàݠA?U7%c_Z9@}PRtD){3!l?@f F=NX殾cۢ;=ôT✋oJ%;h*.9fwx7G[%-*s[f[ %$$$$$$$$hipeKzw=ABNHHHHHH*Nu[|p?me{[b( ,]± Jl<^>~)AQ\E7'dzfWP`c ,bY4Tgcy8gS.IUQ*!e밽;^4 ˙SD T:ZD9KFktt bN$hD-mr11SIa r]%Nr<5R" S5&Jt_AY}^ˆ&b,=5 ghìZW e21ޣn=j( ;4V'IP:"C[00vjp`i6R)v_䏘*4׼R[$mg֧fv%nMm3gKmtĖZzJY"rֽ)G|ˆ/R3/!!!!!!! oͭwCd{BBBBBBB ^S┵Yn%ssckECwt5mML)M.[bzPcs}hzDA #rѡ,fmO`ɚ&8& ͭg8],d1rH٠?2l}>X1sW)r8͢Ps"/ȑBKSSϻ)P6"N[dEǪxKNjˮ_>ih']&&f)S`w4nG=y<ľnLC C^2hGV|u/)yOCEUOe¦hZZ+{z`\r1E;}}TXߩu"9Z{ "0✔`qm4KUyZ.vInónyQAH-yBf 'W߾6J*Hë Ba֯-$,aX>2[%: u68lK eL+i%89*f$Uw IA G,}:?eˈAhdX<;KXJSr!O2Ghi!yw'zE\U  x4eIGP $ߚ RԐ+q{VX!z$e=6i='"Ւ '6fыb,qcNӵ5:iuã7z&"{S,WVZ=IT~g*On͖=r8% .D'!!`b"EBBBBlы|项:_@r'qnp%s9m6|=?:}}8.!a>.r[G]a"3zm~%';\zY.~PQm[;i{.qI`0lho @ +R&刷]y^ޣhbD畃]6BErObg7,VN4SESMxMu6ihD $25zDG[i8+kU6GVQv$R1DkkMprZz+!=;> BSYUߐqAQ꽒vV3a֠47U ! Ć=5Oa4hu/9wW/T2zEU^ *Y:q ieMZd!-6$:F-*פIsG7.kv{ݗIHHHHHHHHHHHڞ/P0qճVw)Ƣ]|B<"!!3pw_k([?l\~K`?)zJS2*f9tN~3ln0, ǂhKd DpZlDۯ1lm'eg̦٨SgSHzlAV]"Dz-<F.LjgGCMVeeQ;c¿Q32Z:_lzIfl aͬaހK#^b }IGCpqI]Zo;&Z|^\Q}2&tu=Rq?Y;Z]iϾ* 9*LúIWM<~pyx4RVAgg%&l|(cIB] Nňgro^F\Pl{`FU{˵:Ka]A>F2jF$ƒ fR!"3C|>A7>&h7̝0?N!;xI?T-SyjoEgl֝B4[~Oӟ$>MH8ev5gWN?F?7lt9 k/"ۖY.8.zQa -tTR*$UԋL葢C' @M ;KGw8)z(s]g;N!W+ }2N*1~jau$x|4߷]|̓s+νL~I-mjqWNe{`綕0z[^5Ot]yEF PAb@{FOC1[4$؊<UJ>F"&rhtn=rn& ovBit7dP_Пa3'dX?4d+UXT-1 j."G7?ctz$4d@+IBLI X2=K@8M{ -T,{]c~Z'8!WyfS&g F]؇UyGJ5`zU.R~'|ro?=d m!Ke4"dElCPϙ\je-pE[F`2h( #JB)4?9RtPz-(u\0qM {ڣJvc'A5MYy,q[UfR =a czIK4;#Oa|&$$$$$$$$$$|cSG7y͗[HBBB•JB'luׂpTBB¿0"Uכ6GuuozxTKJ)WBqhMlrQu9h9 Fi}\>x>&s Bۦ-vQ$v)Ï ܝy$5ۏqrpWhk:귝Q8:4Ԝ^¸ڧ2'2t~#]fR;TLbBר?57t݋ܱNar%Qh_D\kP03q&kfoe-zמ!rk6/hE 7ѻƧ,|}Cu r,9s`!@e m*wH$놶r`c) {Ʀ a%[$hP ѾG#6(CV%x]./^5(=`{$u :dfBVX* v\nӟŋ9қ`E5kCQ+]ukO:gY5$jqb}#/a+0<#8v*^F:iV{{ &{C`xl6agΉ:qXtRf})H` R:NQ V.$mt3B")ń 6?$n.t Yf?. wl? c6+Y?2`.XCKh5Wjktd+- :ΆϞhJ*BTp&;\Gugp8f(esv^, eʥ voAp AsCjB^68ݐ0 [Q3KhU>Sj\cL:вfV;/\YHmҙ[u3b)gRo#6)'`\5Vّhbϯ)PaU!iMbV\R=V60 ax_+ (IGs.f c.1j| U=Ϛ xt2toSB;~50h}=؍ f8<8؇QSDZ1X"@ jDQR("i4q:lU JVR'4ځҢ/?D) KjYzv ;/Rѐi$#}Cu$lBrVnq]?9Wzs<6'9r-tF*5eme9ZX&g bbhM aV-ȷ[u첲|)eh54?9 _b/_dfքkZ[_,{6.sQ Wj[LU8QwQÝsj6B;_ֺ2+EBGDEeF>j3+hF%XSdK%$hZ4+zW`_dD7d9hAd ,JR:mzoDXoĹEvLx v:} "QIRq4Z&|nToEsX)8:y۶Y;hwkOXh:s8B `tI앳Es2 N󀑝j**!u*:Xω6p yMi+=zܪ@OaR>\f;B]C4]h#x4:Wc#}`}x7VzvYap@c(kV98Cw8(/_9]mtQ\#q؂r4+S4HdzMwy0o'6xo>;u P 9!W3iGfSY ) |ÀL63,6EosC^ &L$ϬggyS1bqL@6^;c(W=c}R."LDI΅DQk11PoOQ> .e:JVq]?А]܎q_[Z ˾3GpiJ>un9V^s0o9AB[YlU$nM?2Z5:(q(.]ˢz .wo `αu(sȆQ4qeiINQ4;PKHH8a) >̷c/!$8yr'$8wSQ?i2wejE"39+rFJGk!}% }],f_dS!"qXB~(Ezo}r xT!҈F`5%y8ؤJ-Ef׾c.Ʒz=5JŁɚ$)F,9 uv3!5Eoh@W}zb+WҊWtr%I!QSi.*Z?!'>ԣ{1Yd"BU.9U0@<USګz`VGgR(^e#s(R鳌|H;ȬBZ! e[(v>sy$Ov1Q@|1y0f$;{er"vGRxǴLa,UDXoiS ,;&_EE7}+4O!>z6jK">sP@Eǫ^/Z*[|>eK˖̌>m^%$$$D4ϼrn*`_q>WM!ayYUMPvS?VAh|vĽH{1UQǿ9W.@vK* ) !/ruJ~{\(i|;$KSꌄ &/%|? ߯EW|}n^eYc 1m _0BTπcuUUnң0m#_!tvŰ+eA|=JglaTiSbu`^ + VGU:j: ,rk)Zφ0lb9dJ*aP!^ƙ-2 UTfۆ'6Nu`䮐0v2$ (> oɈ4=]g1澎lcs B.t;Mu?@l/@( p/`O;(H꽑:[NuE|X+#\C5؉=]x̷KP,1bs"ד(JbتE].Dm88}*t%,$wv%$d !]X &Tp瞵([ߌIVAYH/~K:cdOÙFz~<+|îONkFV!= l:}$L_!-Q2 qݢ?% 5F#΍ha2Ϣt? ` [±Dm# M3:1A-??) ˔O%l3i}zwʄaRY'\- s9Gs zcK+ *ΆCx(x} f9b ՑYr nls *F"m?:PzfכSac,#K5e쭻 /{Bh2 V0.t PZ8L'v(Zͮښ"TR`ANYT=yjj\U:"MQ5ډA'kuAj 9HⰾGI]㮝Jn ؝lF5 Oa9QkQMd$<|fűhlMԡVT~g5*|kmY|Y/q3 A}7o\KBp4D떴@ z?G(Ϸh&r;ZR|VVUKt;IK m[i];萣kEHG6t{v ĹO86A]iQ-N{n~Sn hZ`f\+O)L܄/134!aUas^_{"yu#MS\= -5 $ Y{>x~rG G[u7Bq9 25)oq &eT߭ z$\ i'\xyb݇]s[*gM W3I/E6!!%WeVz}oM|{]yA^Ep8pehb/k|i"ǎ)i )ONI%bcԣ;&&`;cgZ^{Vv g f>,h2PmJmDȩoh Kܑǰ։5xK2}0+|%ⲯIӻ )pZhxt{EVR*@cjFޠΖM&)B2NN ..L7VYK'v}RepH -چn.<֜cB1>FUxȹGJJbȵUmg?gˍA0y8 6,u=jOC-w$}>f+tlт̶Ɇʩ+ޢ.zeUsT:$5[wk/iD,tyHpt,+-@{r0! 7UkrQl&tq%=5.{Se+ )2/3r1Jb3>G>mƫ8jbaǿ/-z9^21ph_-:*4 q8w ԭhֈmC\uK Yr I3T:b yа#\յNޝyĿN6ml47g푊\T3(DЂWc? ,uT *K1[oAUwP j[ '<7(#|{M愊+w G8;Q56d]C럒wnK'tq(3狺 l2tiNކW+4hGkbr f; GMijwnwO WeQEM[@D*l GŴVA̚T5pI :r/~IHH~b)nyoB.dG*OICawF P!~ UД=H؋HRZ{rhDh;ߓЍAAbYYR uf3,";eu`8HhSZ"t ٞbp+pX^r~B7dEh-/e 8,F ^6rHb#SeÁR(PfNfǰ~q;[4}@n0&!uӣ5-i0[i-tbH+$ҏq@ւskfNyf7/3CJeNme}.l)R`JrHF,8x ӲkGzr(1Fɰ?pGYR~9#YBH%*h`n"1VߟL6;n[KMJxο-Y`S/v VQeC:_d.%SF. Eۜpm?BC['$ޖyR7!!)B7;N-V]H$y z/VjP/ GV^篳+{ (VD t{$>x@z&09Xs<#U?̻L)'a;?.@s&6RҔAArpԇ} DҋRmR=I:eB<"Ɵ}5^;QR*bB ǞYl/\e"dpTaG>U ͅ:@ mwjl+S9N|EbAI+tTw\K7N;yNV+rOxu/=Ɠ86| 6 P1,7E?BjMKh2<|vٞ 42x^i_r"csLVPΒjYq0b֒IE;v#9GCF8$*g~--9X*mK&JDr1O:ɰ4"VK#>+G- ?yX8#4y`WqJ)Wm-ӧHoPr;Kf8w =0i/)X:,SRA19?:*L|l;K+"D#NĘ-f@*k~lZrXz0/݋w/ꪻ@7p[2U=Y6ʘvI`=G5jDOS"CUub?W}Ju[;Usm36TGڸCm*8$-.P^U3Ci~^{jsn֏XA_Hns*"JIx>IsDaMUɬQ.zTu"' :[ߟB}ƽ\מ* vo=QCΊ&A߸brqMy\ʄ~|O u ^aȲiu_ɔBU5亍?׏^ެb^QD'U|2zQg/ߖ|Еj )l呾3 +׽ cS3AN JHHHK}%jW6\vfT" =NWn|_uxr⽖Ѓv`2) ։U8:!m JFy/xJCZy$~9«[gܳji@p TPW>| rIQd \XseV{g|a*3RR.ϰ1wx} 'IW|8 n+( D6X=caiH|Fjm _/CS_=>aGFC>',g@pqW/PGdh8}8c;i^쨒ڿ q>hb'i{N[=t:WwaD.Ԟv6?hqCG48_J"Zj6i`QAGvGlU!X-zL9Vrʼn|TYdGB/j:GIe1br)mm־ɋ&!#Ww^148P Z(,uNXrM/!5+x81s+Go`] QYXv`OK}Σ qڪWck4E5ˇIc&Ԏ bEe-GEv*yx8+Fsom6ϫumlh"IH S8KB08Y ySqZs% vmsO-@6/x6mkN5B l8<2Nn ۈehьblEw3iQ\i](vy|o3R=IwC g*dzժw:Mzn!w<]ʇbAq~ o$PއѐxyRI Һ{ ]T3Q,r^7|,Zy!((sy41*&\ӿ}6 ёmp+љAZm!ȓO)ȿݿe7=Ӧ?G/<%' ˇJ^mn*'$$$$$$$$$oãao#me>:otb? hT{TLTjC:ֻ:>۽NUg(p-=Bݛ%ԬƾQRI)H@/ej H6tunxkrQC,̍'S^BėR;+dIlG@Y `җ #6_Fs>1Iʻ[b>v&2)ӥeeLnh~ /(6.$Ҏ~80rUh'&?-^q$D$rXBqnRj'R[ա[ ӶHQ%Ra렆 >ɏ@YbB 6-Fl>7SҜtouy%ּmn1Weup:pNOĩE#Sǽl'j쐦Z ZR,4Zp&9) 8}{hi(K%ݹJHHHHHHHHHHHHHP>ꤽ;fҴlRN Oh= IHHHH6e}vmsi dNHHHHH0nR}x#@.lD-gj+wLܬJL<^6~55ݰx N&X )9h;h^~NB]β(<ޒo!t @CV\·?ĵ:!̡PH -| :N9}o Ҕ= Tj U6}ѠccCc΁Ӷ>Ķ}{yT!̵ 8tR15T_%?;sT~MC93rN¯0$ªu6GfLBBDF4/R?h`;[|>N>n5EW#j7)L$;~.] !x!'DVg3 PTɁz|i3W%"025=5kEމ4 fb8ZEJ1.  cbVUSuBN5`@/)UVfg_EȲw3hlcW c+j`6GPFy|%Ƴgu4eWKMG;olz(cVa4JG$oooM<&`CyMkJ(R/_h$^h ѝca"]3L0wWh e`Y _!3`>4` -&$ G0]xYICqid0DJ~fTћ׀:Ly*G? r(CxY[L,f| D^4^Q_<@Fk +) >.H°Z0hgSm{N_HO8c%ܬDq*d(Rl+j] {BêjAp\8TFAg>= 6GR֭*V8+Pa50eXR )9' m8tM{#[4] n\ w%4 q)r$JE998 "l5lJ} ҕaFMq 'c!' MB7 Jxr7c[pO1g.LN*]~Ia+;+e-ec0ENl@BBBBBBB]NH yN>%x'l&-ʉeƄS%$`d6Co}15J9d!Z nhq1czb NÌ1;|D¾.˝-o[̖(K.`T0O}],iq68pB1`4ܾ2-*fPGmRlA-z>t-04HBĎS2zEږ<.-Z-J{t|QKGSmU6,v`8E&UZPik8ejAta=-cݔP[9k[Ŝ ùĭLvehˏl{151ojK^sЪMG2V 5|%0 89'iU#JיγLYy8m1ʛ(6w9Wwn *O]usQnāt5qfμow[}_:a+G"@oAP ^Q.Bn~ T{qm56`cS6u%шM/whY Uq }DҔK}[vתR!V%D:aXQ$1(CE/) <rΰV7|\g^FZUmՉA+"(!K11Ts?{&{(jfQ 'a+&*&b^A[q[oq&UǪt(uchCc||zï~9P8.}A#{ 08P>ig[R߃]GCp"/[y#!Q\]eaMI2ff?v~8E8pLUq tuUKdf=hrWl"8BJCkrA8|d2\WbEs_}ݟ/$YcUeݧC|[yn WL$D5H 00uK2aŒSJ7h|K@ҶaT=`tS=4QGQmWNz@H(9^6tAM]ж_XmTj=Nt#l!Ci{0Jq"e!![7_7,Qp񄄄OM-f]eO4+YN6!ᢖ#)v߿Vno9+)EGx9ӝvw=ybB?ePh>UӋL&8_ #iO†4*<4A7e$TFy6\1fx{(+xRz="[]QNk Ds̤5&.z&)>CQ1t׬~=2ňxb n|ef/cI,&ܬ,JVNv?DǣI5uMBat&:Vf²kiؘ s-yjx;okb.=cr*-8˂,o?( sLaFVKz^7mͭ`ڮf! Ž0᧩kIg4B'ڭLNVl]3O\Hg( |70a*8O3[{_3O;l7YAg}s|iTnP ӫV2{oWQ8 }iELёTJ>v]Ϭ7zb_e._M57gi v3pi.`kW0>N{` -6wIB"<5QBa,yTY4ytfV(-ƮDv)<N NKxw8ڪԙ9 WV%LV'W*fuICtZTr5te<9X]6!!!!!!!cfcoc:Wjq3I.`{9r+ABBBBBBB;*:6*4zUn랇J_eQ jT,}6<_>usNf"9C2vHA:͎$pm:q%& '8%~  Rt2kZ rb8SCw#PNVd}p%Xx1}c\g_TMurl.8tz!A3F}lrü b^[Z#۷Xx2OZ~Ur>W7SbBקh0zEPR)ǭ4OMj9 }cVLf¨mcO2 jOLbuUK!]r|IHHHHHHHHHHHh;{ s8 o˛R6JOHHHHHHHH8]bp]',ݲK>oPN"fxHa裘ЎC,x8P&tztVTa=Za_ 1NU}5dCF4uc"!m XA\fggZt G@`X(`y0{!8?@#Li -aB#FfkM7tY´sV1SA]Fꖁ1[k9rԀ)SFCظY}fg<˩ ˼e[XS[;T!) -TXԎӒP2Z`Tb Un]Nc\,0ά&`E^r`C/U@ FC?p8JdJ ʳ1 -3+=wC{n׻WP g$4ZfB~}Fi' p1.nG=DW A]|np]>7_b횐Ѕ?5K}T9<3܎BR^a>\AɜV1*:e\uVHO/4+*Cu-Yə45Z26@M?^00F uKæ@p49cԚy5╯wGhT0z˜:VBXI= SHIy[Iwr#;bt(ZMme-o(:QŔT|B tDLjjO nIM6SZ+G@1ѕ P2TVYm'Xc4MzT6Swֵ{pGNl,ۜ[Ûg4~fV_ALHHPS~&CubGßѝcR^UF4o2E}O?x}Q{߂0% 3 C?$K*Î>q Oc;×I>6`Hל Ty K8z H}NږZRϘ8,1ױ2V'5b9 ?F#<0k5g_Qc/#mC a!3vB1Yk4C ЩP!3CC>gnɀ_j=TT tk*UAiG1m'Ja@Hab4گq_{r;ahH* -]*[z }v-)hZZ>e0FPh<N"ۊ]X;F0>qs"#&Ax܆H"J̰4\ǤrqŹ] h;!.XoL߈[SQd@|2ltMx>|!& ] iQ-r97:2PSRCc2FΐdclTB<Į]Q G}rhjְyH-[Y0]FHd^c>e޷{K\ޤUC 4$P?Pz=Zɋ8:EF8Mv)͂u9QȣB{uhaZb?ZwR.3@VGD@T㰧[=C#Η8eSF6m-&97-8 ;1% ()Qmѱl<=ofpOzmOGکM+Y"KF55Y3hCG D]Z~әuGp3#'!!pLHH\&iD~Ϣd܎G{"Pv-XCol8}~'hN!9Q6[$$$$$$q'$tcɊHyɍG( ю4Gl1zlDOSfP]W;L4J*?H0)Bf0#vܮ܁! M o74')V8|-ʗ'Ϋx2Tܞ"YB@!N5y_4⸾:rּzyrO@YZ6!Z Yy,8}c 57.Bѧ? v?>Xq 777 C(.,^$Rg0Z D(N+R3yciMpMmA|D-ǺC;^HqaT`r ZTk#ng9iŊd zHVC< 0#4iޕI.<PgdBmc4=% Sa{kv%j#3r~ . |eowr'0Nၮa%$ Eu/.?,(Ս c Nq7AܠSZWW2 7F}~OLg"9+/,B'346Ԯ/#^!o`~i"nOU16~0]y/z|19'F@A!0^ÖE0;8V>TU c_EoPF~ԝF! x@lbG{L 1LI34ǡ|H+2gwn;=NOqEaJ;W{scl"!FIAp]3y +`\f,5ޚ+=r"BԙFqi`3[V/ 3:Eהi).#>qf#G%3DTau\Qi|ލݔ@Lde*s`4_I{?ڸ^AƼ%MxZZhݕ`9y(悪?6Rմؕu588 {{l۠XJ ƃ,lAZ$uE( m_ YUbL莚$ } ~K5(4AФ*PxγuFKZ5;77g?ܲ iw6"XzN桕z#3)$e }01 0Z'řxzֿxE1߯m= [왂<º,/~Zsׂr!Q1m[d˜Jc7^ oJT ~jGŜ.?mwBR*M$$|d_ 7ϟ^i=~e9挬{ AMLsC'Hl.Z_ YY"oMQ(@-}eaRA#[hB/+u߮$1Zg -6=ëi"nIP{22ȱ/NԗdEnj䜡1ZQ-<ݪr(L}@K9 Tzw-sW ۚ]ߢ҅6BfP,eMLU^6r͓B'oGL[ Pa!e!C:a|B_p8ƟlYI7zῴ>[(&#*ܥ EXXkَԃs*3 gRqckkhG;; ^Mw:&ML`imF6];>OJs*R:6s3MM"nOVJ?4~tӴ0N Jv*? '\#BʲP;GՈJH : P h0<3 #n7t_uG \=Γ%7#GkڇuRrV,Ym!qƩ1/.VZqU 90͓V K٪_#"_ġXg@gql8 !WJ=; y $۬ |Z<}4gA)5ˋ`ʍA?&#Wg9"?pwV畨y,Vv-C7ĖOoOY2BǝͿ>@AI%MA/`d‘Ă呸Ig+7 W1>Βڟ׳*1MF4أyi_'D+(s:\\IO-  *74Ko>Oqq0 s۲$fM+Ylpbz'z3Rvd/.`@?AZLbĻЊ ˃XKc c\;b (ȠguԀ(b2c֎@T`lyg5Wex| +ziy),ŷJ $JPv[sx}+5Ql74-VKIm:O|lGbF7koAۭ~ꩃN^PCy$ȹ0,=LA{B ODwea᮫969RcRbj kmhYJE\&*շ.ȃnxfPPXi'cTxg57{,&bwAiܱTNT+PIM \3 Cf~=^Xz`UqC V8&CmDpelh ^QRCzwf9O(m*HGƩPCa؊ϴ(v)TJC-gxFNToM18((Euf4?ߙ5ESit2.JuyЛ|*ɾ}a~`4^I#(0uL!N`KMڒgM`K ahd c_ttl™0*RJjUs[[ 'qAPyݍ1y޺<:,7oY"ȄW vEzznL33_;AcW0:'EllP0ovqHh$t^Ekgy5ͪ@v6E~P(1+h( /Q8eƒ/ )&QEMջA`&Z#XIT}fYZ-!}lQ_>K5{OU¯ 0o6Y8?ώΦ>?*Y}ghz2x|GޢX;ߌk56qGlm|GӅ't?A ]Y$mDD `KY [_ #C2{P\th (xʦ9NھɎ:yj4X8a&q\@_͕tRPڰ^ B8b@,rŭ 1Αoce)r{2ADLs;bhxsk~sjNnrj~xl<ݣomRo*5 3J~PƦI+fFNBBBBBBBBB»+~)n'S'$$$$A/~}$nLHHH8A ȋɐ MOQ0m}v P|=h+K]B kڬUaՒ$mlzY/JzմSLF[FlƘaLc!aUS[iF[ge]GJG:JQ1*R)PTa2"wqB␲ nM;ZC"\.۬02(bV ,(<M;kq tTAzd+ݠZx9#~?:#t{]0;jht|Z+=i9t"(lP QyL$A(qwxW :g|7sn`p^aa C^ݠ0ƶ?;Hm :ehr!xLeY^lϝb˳wgR%ƛTTlz{va8֑:"M)9:Fxf]%Ԏ:gC&V+#!=9ƌ\~uQ"S_BYSIV#ƼQ*$Ġ“Tk +hŲp03 [,%p⺄AR <-TE %OrP>d;sEgBK5EkdD*۽Zֆ8:M*&U`Tu?E6hs<|]]U=c/üNq,!Qps7AK˛wZ &2 'džcc=p\MPҝ0ZB:yŒhIHHHHHHHMf,|_ج/ޢ7 gemK;֢:xx[xG+Ԕ"nO_R kCiSD榅( v;rᘮ*;hC/6J}~6[Vh{Wp(>p>8@$D'3T ,0k&qei7$:㸤w93r;H-BϸږF%Dʼn俛]KOاk#K9ñ8ri@0x,d%d]=+l0ɤ񩡠tJRx|˲z(0h^-[C0ι%3!+|K"4]3ڭ%'Q+0%t#0¦KWlht;Ad`z٣TwBFZ(IXބjbGt.u㷑I=O00uCIHkjps8zo:HXuo%bQ |M44mPF~Eq Ef뼙$݈uOޥrd!K%$$$$$$$$|mB{Dplݡ?̶pfqA~ D71ki*$B0N5|vLEy" />m|26 ,[:0ŚplFFI򫕒i9{E!܃އ>е;,NCBQpR)j<4U"q"*u&v[.D#b`OPW| GC߸qۢV`~ZU ^on:h{I+g˱T~P8=25n_UZZ,4GbiۡtwZ7%UFRs:eO5ѴV")i`4"!UFa=V?%pHIiqg0D~<5Ya,!]Ma[yqtpqb5Oh)ҽQ4tf@4=EPYo{!4jU=瀕 #:ULXV4|I _>Acp%r CjEJ;5jmqj!͋o44[B<*Z},Of~>`FufB1}\aBBB{{rwSId@,Dˎ5zw_ʛށUU!E&ꕨ>9e>ī>TeST\未>C4x{dSFB(U&[3/CkĞ{+ @ ^~I+*@o7!7\&q>b[-)-c"FcK/v (n3F`)Y&rk[vzM[777c_~:i_p $u |;e)WhAx3NjBFŷgjY:/\jLcr"D}yh5Xϻaԗ|YPޖcpo!ƓZrFZsgvqÊI6>U負:u#Ad08iGܙDSe,uֳKI!06JHs#jy+~IHHH}F?ΪOW>j6 ^&;#[hLA)oHqՑcR̳oSBѳ(# 2IC5څn]!. t"ήHCR|f#׏!?!7b=㔵pZf,T{QiBj&՟8C}U~XaWh Qg 4 9qַRj} b3|@5#H9JI kŹI. Gx N:FѴEUBٝg)_(Th[]ՙiG`oW3)Bo#e+8JzUOW77T) N=Q>}_4 2tl~_15?\)IfڶGNBBBBB!O$$$$$ ѰFsIHHH0Y?;KHHH0@}&`$RꀦfHMn\u70;!!l1Ti"a}OVfGܗ90#Y jnDny-c&Vj8٫qQ(kgfwJeX(!5…3K۠iv5?Xg5PFch|4zS\০B ]7vhY a l:觲г4Dgi,d*G0^(|eR߀ޤg/BI6Ai9b "NMT^KsTYOG{uf#^qŝ |׫fہ<1P 6Y8e{z߻-w\zM6g˻6_D9ceG&u1@I/5{xfW;U%51MZ-BD^Qᓢ)ɬSO~ 6jEM>fzWfk8 SJ^=ORoޙ0OGé(Gi%q6amq-JU XM$!e; v=G@ЖNBCV;Qgɂ6owoMIn^ -z b8kENBB'yQÆ2Qm5!M2;vVkE!5>M~cn'?r?qw93W+q\\ilS<PK-}OW]&ބ 8t]1HS͇fWkTE\oe+4=*ů%g*!xiyF%P90DC3XL5!t&<}3p)7Qyir-lcFm>tC$_EnʘY/Шz:Cأm+UguF(3"me%ȿӹ2et!ti!`y°r9{:63kUOOL, ik8 6]r I.}Alq x/7DFtRQI葱ʡk#-ӻވ:_ ?l z ozTrbU_$ԉdUBfgCsxR 4]n0jg%ǦzD|6)x[,}B3ptpņp#Sv_rHEJY Uզá"1tTZuD-u'e4/Rg|;3:9N-Z({ 0-ݸS\SBuX Hi/|* @||W'Ԥނ.R˵"L2i7;fe[2bɶIUtWG(:v)Ç0H1Q?jQG6gB3F 3!/ gϫT=}ˎ |am1gU@q 䐦9mqܝZGIMWm}ha^&g{{[ljGy'v9wrE96ĥ&FwR!+XkW7h+U3uô؋hMQK&=zV.z$$$$$$$$$$$ˀ{ٴ?`9>{}BBw"'!a[:iY,[va g3,'$k Tb B ?XNJ[J "7[[51T,ؓsr&H\mϱ=@^;QsBAga1U:)z:kKtMC7_n}R,1Лu06.(DSӑ,IjTA%0Z86ZQcwL)yq6] A _NF> C,ѭ]Z +9D<| /橜S:hIB$mUp:ͥ`S1q&Bv$R^[1JC%YlIVTtyUiew7mJ41Y֌mR[bêä6Fx@nOD'N@TlhP Yѷ:1*ZC# Dw[2Zmuz]nA-˾У k莬L.C+G#٣\0ͻ JHHHHHHHH75}mC#/ ,IR3BBBn?fI8Ώ7O0<]:&h%1Y_SE-],dR(>ќkvlcSƅoJI"CFTUV!@.ud 6hfAK {w{zߏiU09E~a-ӈUΐI#-xJ|zՇ=@ǗV~ T0OQ#B_˩@pǨ"ap\fژ˽VjN5{qTZZ֏1{Kՠy+ig5JhAPMt80:70x,;bʪS;MH#xP?PBS4[K#{hՍ4T`g[0 :$4o#a׸#پg9*ݪk+7ZBlol/W2CQ.!! ~zy:]%1V"I50|j)Npa!Ar;a&T':VkѽKBvojs>KQ8R[#DW <-Lb _-@eN=GXFZuyb/Ȅ}q2M!L=yĖO30߰r¬: cdǏ:kqj:w Xp( ylH\:=UlNYʾ.v`,rjz%[#4/yDu%dJ )Ps7&6a%е+90i0EMRˆU_[o5!LM_nӦ Jlj`zEhJԫbᕺǫAuk]i]{"N;g_"}qS_N^$j#OL<-) ԅljOU8ЙP+D ?k>sgz:>^a7XUͶ9 {HKRo9 ]VfvoW8dikGBBBBBdfQ*: DOBBBBBBo7$"pW"';*!!w }jZ4JH8ȾM'`x)(793ɑ0m$cuyZK̒NfC]e!XZgI]H&M˅ZW'h-b^cki7r>jU_ӡUY+ؖicD@|UݪWA"AIq{yؓ >@_WMޥ@MjSKMx1ڞg dl_dJTH.KQ+ѩ/GE&iz'E_Iw喅J[Ƈ ڡhgo6wN~7D_0 IGU݊FdSih/Xdm CmxeJ ,-j֨$x؉`ul]Y)Q :ux[ SM]1AGMoLpX.K!RlE ##mI.kQ4Eð݃^q2oЍPJ 0|d·9#0<9 hDU=/YxPipAlw{&O EVI60~6wo2o8cVw8oL6gxؙh OŦ\B.|IȖTߢƗrowZ8u(%Zc<~@Y6 U$K)xy31q(n#w*gVPGs1Zg"tj-p&FFH,&y [/O2s)'BXDҁGoz8_z8)h !1ءVXM/93"j ]Z8vDD'hy{i7y:aB 2Y9ˆuָߋ\h2}Z3 "*Pn:7xj،%0nxKȁo"}(A8+D-bhZ-SQk-Ksb1F#5HJ"/d ;/0^br!VGVzhbÔpڤg0y#2]ݧh 'yB6sQA?eӴ2zrA/V &槩 1 YZFBpNMJHHHHHHTp~WQFqfc܄҄yJ&4WLlZR"'i]nňZU)1_<$PmCFBJJB%KR27=D] cc>fq;q ;dUz7CQ*Q͍yՄ*Q^`T\CI (jUv3zsFm,ymM 34>ျD;ʔ#* 36C%wͱC(2] J ?t=|sZ6L5ml0:Tj zNSZ]E"̱>mh\9^ol3TRt=3nJpϵQw~XѰ`c5QA<.EHz(>(nF+ƪAW_;m6C5R-(cn/q%Q{ Etu`9ܥ -.Ip(ɇ]M9LpBZDLBPw=ԄEgPMl/FvZ$`01ƱYƞ& bT9k?&[nk]$KHEe҄z[:^͓\idI%{51[]$4蜼%Rk1; 3NbX$8ʽTyaۺ(ʨ+ZX"Cr2@jЍpCBH56~VKmaN-r0t$P"ӑjG6S{hxEٮo NiԘOg=9zh`Cib|*-@O~Vs|k󧵻ۗ&4U2SRyi7kSM=l ㈆U쬁 2&"9_ rf'|~k6L=Q`XCQA3Hպ < MSY|jY~‡"j]^FXΤ|4d6m,i_1{ K?SWdP^Yx8t7~,ƿ4b[8ٜayx")E]dX:ԋ*\wcZbH1gKjyR΁%+~2ښd3v}e- =8(bhy0U䧏h9kLwQhHߒl%&spf6ld/Ӄ~& 隤N g(t4П%՚cL7LWlHBg2.PKQ-m~1KZ̃nOz&*j|q&ZYo7A5>۱ nrK{$t-WPW_=a?|DC]vgݧӼ&mb7Gx;؝>~L^jYJuMKQl #*[?:M2 5XwpTzjuDP@"n -_ $z) ̙O8A"Z>[qTY *~[OW%뫰OgGprlO4`BB2XoAJ STP3U,jR:=T*pXFs$(s20Yf|,rfe~ iRnaQ{ڭ ,Gk(zҥi T;B>Ess@D,*pF߬q&r0!(Zx-@Qӆ}xH5@ٺKG=ӱ,&e@3̨˱´&(i4^rU{nb"Ua3W Ν m+Jō婐fWdh69B`氼 2ӷ&kwJ]31p$m/ gpOs S9wrejjN31'eSc4Qp}yۄ#Oa+Y^:"|xnz[᏶z p:Q@x 0luemkai4m"ig滺b'REn=X,B<<(j)="Hqi#pa`aH=u8'MZC[;ns> Tz~ yi}J90t)"WP^왑АQp@vkqKw4);'r4YF*o.AR۠əxLp`6aȪh\=TqVH0?&ţv+Ϳe}(ӄlYSFJ);4i])Q>l8D^-R**u;E;O.(@a{~Ѫ?[_KB’! 54{v$KHHHnjUnQo啂sjxB}*^o3kE`| *R8pupBOJg?\mb5nD¶|d_(Zv]͇xS`'Z9 I[wt%kyBX5 KWs6/ґu|K=ᤤb8bgs(R99 ^2kQ[בjW7'ǒH hdڽIF I=n!ʝ{@ȸ!cO*4TDٰ͢J9+ᜌ>h?(/2#_nàsʽ0"_KuغeʦDħ>&yGOaf~ELmXF2mCb’8͵ϚkHq7ysnҫ'0 EqLw^T<0PW`3ϗO9[Λsm+F)ЬqӬA `Kڃ5?".*gn9Xjs~93,srws6s;iOɩ\7!N}wwo7-[WZDn+-/$|3T.8ø7 ąv1ǯE13zkc9cZKwnhiWS-q4_c2z XAJeT.iɐ4y%r ʉI_7[ë=F,Ԧf$;U1?>\vAIv G RvK# uǴ[ZV!*Mw!uM=R)1#/?V٬Ut57O;ի4cr-@!AF!Y56g~6ʴ=p]Je &<26χ}sB0Ozmՙ&J༁Z(KTlE;wv0}Vs?49wֺ)tzWOH=^䄈ΛO8AGZ8%2]K{Cw/Y[@I:H'7μUUeJD5l QUphDEE+MT8Ypt?ʭQ8]4^@D~bOY "cyRM5%Ȏbg6 ;J&)8~[r8$/ 3_V8Jό'"߲9*v29|jm" QqI`[%  ';vUg kvony4lC4:X]wp2,B#X!wAg4Mg.%).`1,{=+Ur?xgdRMQȢ\3o 8QGŗ1| 7}ZS]΍"9TF@LgQv k;hi:d>>^B"DRI. 1D'q,c;z|ˏކֆj 5󍪼DKh,ɫ"Ĥ\;k:Ji?Y. G>_ 3)6waX;07R'~4zvАF=aLu>y߾ +ü<;uD8r ؗ{~79n_HHcߩ~J?Q1Lj9Fc;=wp~<_&o`,g%=kj/<ʇ^o9:s<7Q8]ɪkNmT]9&tՃ33\=)tx]YLdU,tR4D$ 4&!FK&v Lp4/Ѵo`7Ov;Ejjep:(H)Rm˿\0'o7{f1)/C(sAta<^'|_"^(#`yŰo g5֎Oaڴcu#X[٥:nzhR8[U fŪ:èܻ(oeu+r ;lDo )|fSWvϼ8˗U h'u{4*d8>SU* Kc60=؏V>ɋEgG냴*6! {6B/>l>/o ;(36P Pˀ`IJqEdH`4Q*bq3p`.iҙ'ISA%O>,)U !bwY"TjJNyǫ~ERDJg$6:f)LL{ PVNISq 9h1~$!; tF3˄i@0b|V4s!LF#dsC`S[JeB7,I0|O_9 ^NWliwם?D$KwD@7t ʸF^ Y,U]5s9E7K&J:gZ`Mqcfߓ>kMjp"[$hCϜ?9=" +1uC1I8p~ b`k.?p tx z&4N&J́B? f3*c\EhqeYe*M0?@␈,G#r ƭ{W/h. O.:\k1JzyN?/1@MgAdh]*7Īo$ H=la_84j 1 t>c>N2N*sm9xʡo`:rg_ÍKn:sbex©0.H#F|*Rɐ dgD=PXn|Ɲr2{ش@GBO((ťF)p̈́ռV S'""K[(*F*||"g="ûG3)>EI"fsd1I -˳Jo4Rsq_5ZyR1]9^bu"ܾ9CMF$s1/K _}^|Y}tecae09s1s4.r4e烝v#S{\,Zyl@i{p bfTG~!Fo^R({ h(ZZ BurӨ$V XQwCRuA1U(hm >ؒ]lBhl`thG{̊XGpph[v}? ǣoؘ \NDj,Qi34RH'IjfMsSFm4V>=Pbз6_0FRa!.]mٵ*U[,'|qq3fpu >ɿ ی> +l6[0NA\]QmdOnO6gOnX[)_`\71gb6z og y1Ҵ2>;5J5u{rK ln&wd$1w9Tʄ.0AGPߴh4ڽi.u@{][,2/8L=ͲҟlK3AyXQE'&q9^O&\[S/QԐ80aG)JP! |Zg#_5 c(uʼn(h 3ra3ܶ)S[iK7olpmۍ'AQ/%"s^@ .d pVǔtn(HOuQ9?S|DžYqCWI`տLH uyhd@W||W S?hz[&BjQD.ޣƇ9M|iG*H Qxuydw2æ%o3j7Ăypҳs}I9N⥵,F]I=ރW/wt|6#Ejnث(7gX>NO?Ea&$9/vL!߱ISҧf Mg4IGFj:UdYْflgI*8wHtL'[٬ZIr_OZ-aq v#:X7IXYKVj(a?w9fj$ і ':ijTTvp@3o*3_q#:g!OڦѕvrBImG3YCr"QXjN~+I%ʢ Quj@RBēh)8WmZѧj( *P@##Id=@(ekd&V0D#8f! cjvs*-v- ›R'K~ڛ|ΜMURs5S: [mZX4 I´.b\Y :#gc`7TJ7&dNjqngeJJwMN1uTsc[3h ?moaJM˹ncD_9 _"s;TKsa`SV4ϩncW[ ^8SD&ƤӲ̞(s1ׅN mB _Wnoͻ.#_l=/dڜۈkrvi¥LO9uExB{NSem 3`*/9 ˳a)?ܝ,n8[[Wߧƺ+5}:~HRqפʃϕғ Q) P?JGnp #Fm-~Kr#`0 E8NY0U@ 5i̭'vDG@lI7"j{mظF-E.d'Len谍# y(3dw~8 eq 6yF"(g:fW`{ ǰvefCDİrݏ@X(UmD;)Be##vd.Jg/ڪ~,ExJ27e-[T>M t9!r |adT';&ZHdLkg-Xނж ;kN#ABt5M#+].4XUCPq,*g+fֆ@#vz:} qn(P"[+m`Ơ0n.?pjNoT8Q")k; eql~1єy?[FwM9| } 9qQfI/g'Ӗ[oF\֜d7+L`9*&6;LU&SzrzdBH!5j/-N|&QOy$,e P.;П}끌 T(#)> 7?-C6 y ؘi *RZi4yB?_g;`c+I)63_sp'j zIkbrS~ׂDWlE+e)>R~ Ԣk\Pz0͈zO$QRN%{ɉ$O NBȱ\r:AUC+0sHE`&/M0) sfQ97X F/t&(́''>P(CG٪,|}bqEhWR ϴ &9u2 c+U☡R''e,E,k;B}A&9>GfZ, ΂:׻u=Tu{CfYU,B<>ODqD=j\Fm :byl-Ou@oUyVށ]VѢXΙZk7 |ҥD,|{=Yb[M_ +x\19'?X5ʝyckhcTJQ(uH- o&N5y1YʋS 7m^*']7&u ҽ0S(yqރST}6Jb,UG<[S8!ʏ]M`3TuOu. ^YnR8Mq;.ꀣ+RY==֯,d+ *=ss+9xٱL^r0EI.;'XmP!9a\rbx`2X *m;B8PCN@-[Lo >9W8mN'-A(H`?NgaVm%!\po$?X:ފ+A4iy Q V}& l<'8؃"Y[ͥa`)K,\DJ{S,1(;U y !xJJ@|PO!})m]V]Yo58zNT_ޥ+!-mXZgKCǹ5 MA;؊?• Q`U#T,f؛A, -;G^I_5 s7`#bL9)kYtVILF.#ծ6?rLw7Ba)?P^OF> N7}Uiӓdp|pd3½{>+څ]GU.tbDxbI7 sRD昲3gD.Sa]˥8{Z=2 l}ZFdB{lJB:pK.-|Ue,BšC~h,D^.B| o]Hdolb`!2Ϣ 8fuq$$ E(5E;j4=rx1pI܀9s܋-#8s31l`T'mxfapd7O&k-sj&dr$*jQ&idIFR8Y՚OA/3%B Lmiz|e !$6|YX'L8>#,Id9h˄,:а"Z5bҩW I-V5_ht 5y̪ITArΣ[LDs"2l)t[)ˬEhR87kGKOB\(Qb2VmYwpOǐKϼF`OM,OQ t-Bc% :*wfҠOQYуz,ހ2j*TV]0Z9ȳ%3~ô0YCE zB _F2GZ(Ya 48eRPQ/?qD!%;v)9&RKm/~FXJ7 PlbD<2:1*\D}1ՐiѠc."=v^#>8=Jlr)q)~슜ќi@mk4FLͿ$IfcݿL0.y wAT +y ҄wPw`LXY7^a$Ј1q0}=~GpWrfHysV~O1f< µvK/#z<>nyraAx"ױWso/òg-?{qی7{ G1CA;F 3 JeHz3R/irlY`G{c|tIXG߇ŠOWQ@dj: {/2,F]qZ9ڪ%H;1U0ܖIчZ'׽plzϘ[O78L`{z2xI[W9.9c 9!zOmEhV%j8P~ aV G C3J\(1oGIm[6]^Jcuv,>Gw<!=pӈxw?LmvNir NM eLU. ]vd\DL*sK #% }D[Bm/kgP喎adW4Kׄ,|^T&kj'*nɼC_gdvSm>) 3J3e&(:R?n=`Ri8ZဘV2sdUki۸Gt5w*6{ W6~^a *ExSn%9Al NSf.)je4eH'o)^)~I.>{ؠ;IF&-ɶZx,.=oO'lwj Fڤ3x@)d+Q)I7UC37ׇRȘ=!#usXCt]GG.p8S6RJ^"~h/uDĸZEɅmuH@]Q%3`3qPh ɚUCڙd|/@HA 0x* Р9JEqlwn҃'6H2(x'ۃm>BW/=ɍm ڈv3nվgK q9MΧ!TthT[{G Gecѯħd]~jNṹ~{B'5㟉L?fr<ԭvnДu7Boxt+{_.l\ÀRxЧE*m$1X$v]FM 5u„ˏ"Xm@Ł עЉawc_s96,=@^(%8k,Жxl|%$6ZFWtoB/ ,Uwm!ۚчܓSbsG=O-7RXj%}$B֞8#l[ ^ ;,t 80X= #b w)  kp .C0]Y&,<%SYR ,0tcrН,NW~#iq ꇗVzz_D0Giq;}SY:7a0-s`wRόq#؟- l93>i߉gF op3jlU#ڱ Osͺ/{(r?|ubث?~JS,%VPn[_?\Sey~~ė.-w8g[x&d`|>ƹ=ׄBh8|w b< 8[[bpXs~(hY<[N?j#(h h Rb 4Qq-"  k c4zGEHU[tyUF@}U8`޲""=0`QnV gH ~qL8vnṄ}`R1M|tMm/r>w]g {jG2d'ƍ` nCgoQLq_OV`3[!CmDK'bt8^ddNg[%%)2ڸoGH,LF ,RY=rѳ1ѕ Q³,}ː] ~E}#,9ZWݠv9CQxĝ2uп \s_ OcRԄݢ=` ;,27b=WIL Í4LPT4DUh ȱkZm_0&2s1sq^* isLPq!9+|T ?oxF\Cj/'e0`z׈.r*Fa*k>^j`ŌN~NUҤh*pCweyfIZWjt +û|m@U|um4id>/e+j59ujH5Zz=[A)"뎄^j]U{amϩvd5fI3Nee7`UfbȄt '0>^qR(x,NU_`=9UA ODoQW8Gz .2́K3$a/CW!t0pyjmsn}̢2%#ƱW+;$gɂ[ۈ?^ 7-odFsGl^؊8w8qX'n(X h)潑yg;2ΧʟS<77tk?z5Bfk܇zO`5Ep.r|gAc+[$/Q<ۑ8f jY=BD~Rl#:~;"pǕh=#C:8Zf s܇x[zy pGEN 3/ޚ ˽s~dp=[0 Y圅;Ȳu<>띮 91㋕Ue;8qb{e5?1@)BERpNyQ\s3U*bYC-=)׸4oNnZG~ԺRUQTMChnappHqyC6CArvAN=V(e]n@+nD}"fx<|F^4\ jNƈGo"Q~Z4ؚ+sD 7 􇵠N,ƉfxR3sǧz+l6 SH o{Lr\z&gq=:YM[Cl?bgHУh{Q[e6Q? y ]-=EM/~_3#Wcf1svpY/)256 _kFyJA3W_7m8c`oU gg5|vys{(ݯvvKaSǪi8!cčpJ:<H5gh M(ooMnr1*rP]I>FX IeUeY@fԞDm{{JoX7 k]H Okސ*X>6Ĥ90l UPId#.AxCGEYhY"~_F*=|F!C>=~ŷ+?~-:,i&)VU.es}[92YX9%oeY}9 n E8^b9턹Cz5 ۥt-qK7s#1= *uV]}gߺQ!d߶X C2]R`&LN>H\ױxD*(6G45?;Cl;D4MվiZ&0 M :):!rQt7lS{`׺\ cFy%Jۤ!2/Y8dqEʾGVby[ٽ?$FGfc.0~QNl!+:9.$g,A}[Fihijp.Ai9Ut kyB1K>:WPo2*OV'mįZ@x ;zl,]p  ͺvs KyS gȫ6n[)sLw9x2G,U,IU`;!RX{aل0~0/pWPwv!dת~3g: {p?P!7/}`&t}k[ 54}6Ҽ_"G 䉯5TKQȱٟ0/JuCXX=Ng*Z~tTlW\}7G T!Nl^Tqv̤Ez47_ɀw ?*GP h}ȥr3mޫO߆+R`CNh)MLP44 5%/\`:.vv6s=SngJFfE+ F?_J/2bg6dzCb9/||?ǂ^Lۮ +PNjV/Mɂ[28ûY19``yQڳx)x/?.gub'wƏa)euy_7<~aw$yƜ%5Ae؅^\Jt :*:R9R8CF1ӱ3BKvȦyp̯"Z=ԡ;G@о|Ab+ڪ:Yi/Rn;h϶9p6¤J+r7RPN9 :vE/%e7ζ`383B! uMSf6`p⯠ KDrV%<;]9J8d8xaԑ2;ӗA_xJ]; ms/;$(M=UGͪR*> pOwx v?⟾ʯ+~U Ң35E[گq ̴*kչ%>xz>,t` 5|p鲊.:w ?8MP=nhx_K_8:!$wZa$VΒZ.ޢVs",Le9Cܱ";6agN \=(d1*O¸o1 {U6ڸcu{MSˏ*B$Fs&<:)e օdVA,$gܲslfuh f6~%ݯci|&%lz>\"BXsq[q;~}J܉N=1F~i]esJۨt_}`ڗtI#HZxAαR*q賾caүO(pxQ`IY{QG0d >2R5 4^OhrY.fr#!BbtCjݱL|A+)#b-S&g!C z@bAZ"m%ײQe-y3{YVem:j( !tiR:(6;{C {|QˆJ+Yhs@y5,&`,o,o %$-`+{[Y+x=%(_x$łh˘"Cn =| ؁yBg92"Bv\ r_lIu#g;n09=*T51n0FX6#FR‡ZN,k 7Ak: }v8#h 1aµ+F>a7=- Sq2J<l2C4L>0`Qz9_UyObfZsǘs:F#)6s^YpV"/ y|`Rcnֿ77+ ᓟN/ӮīceY7=^1#-)~>РUfoOAӻf'h:}鹿O}nq>JY`2:hmhBO.}n٢ᘿ''Un+| _xh~?1\6VrN}*{ ;;d_8p0$6OI8*c_?4c=R.h?驶s^u}i4.O q&GLkYCϡ4݇ ×+Rș>fx%'ܥŦe:jnk;b2L` 07T٭t׃Qj!.;F'j-v7"71l]@%]/_/?/ґ,&bɫH ( +D {!GXOMZ뛡V3ژ͚\Fi|Nf}U;2DҌQ*v *] s>rOUÑTu x+%@QK ٝv;WUh`C^^q!j1$3nxE|q˅xuʿ=ZP8m)fH.aɵDon^pHcj,x']FqlFՇFp)ԝ ~KR)hn rN|qlΰd0s_֒{|O($V5@za7,5O|F7y4T01аgD+ $(4l,Qr>D!zL`+ey>Ss_X3"C0zdY:)C.v',= eȉZ{Ejy;mN ؆'** $}oL;$;%nB祖r>b|ZKʙ`H-{ 5l Ŝʀ89H݀F[OJG@\|C+f#z Ah|cCYK$wapVׄ]Ck~= d92BuEYkTxP{vTXd29I%9FFK0} <@pRNoyRΏJm064&/b2ǻqK em/&Z|hWYn%mY;gsS%}sƺ'mW"&{LJ=;q̟uE~qTh0u,ec*981^ܟ]rTשڻ??r~8/#./$*WIRH@GX /d^3P8ս wA5ƶ(Kni 'f3}gpl^;$)J6 GcZk:KF`M( (:_Zr>jaoLen@${4,+oQh~l;o5vn4L})6;^׊S*\ujUnXD;~lu1J[^&'.}H1'o} S V[B:94 0RT;w%U߫.tGھFMlTԦtM{ i0-P<[fd<$`~h?@y&||}g̡gxK)cut9莫 Re~p aktڼqY}SUz!'_ك}}okqT[ОE7bH8m6i~>iW[/3ƴLAM1Ӥ0l B,v9.E0Rij6딙}K't^Z_ZAF}< &Yca^=0?i;y&a" R;E?\KƌD( ϓQK$eTr޸͞؟9γ  f Hmp&'^i?Pla  bvAofXH+(K*SY_- N]d%ZO B1wHh-fA^/F5v%,*z[Rױ.fn C.v>m9}1لiP0C5f;ej>R'2q}4Paؒ 6 D&p^C+rR>d̙Zf8cgJ:?RNt[ᏴM8OXYRzP>r\#ǟ]ڨDWWaeJ=W|4n90ZB9όG+&IRTỸ9Gni>TەBP Fa¥q[?fXQ1:6 XЉ6uUAlmQqlz] PHJdQxV `;\ HjY'ÁcV#b/}V [~2%gP[QB3HdTcz:FH{Lh9N[h`95@5d I{)jщ5G?V]`GfVO ,;/Kw6ߏ|0~h;6buY9l"_WEspGyrȨ/NW?s#µzRFֿWIT(H凋nMERˮ=\ڼ"fNEr^ƢiR@)*gi +j y2Mu,@?XC'"WwMON T,1W6,: }-He}R$rV~LwPk&>Zh+YpO0V'9~VMVÀ`vM2Nm\u@5mQf rWWhWʜϣjoHkI##84R&2 bl(ŜwbO{OJS Zf;5pXR`;Ԋ9bU\h䳫Bso_a7U@$NZxzˤ!~L&l2: p =X\UPY%.T*WVsVNyWU=H$-Q>3!fEMNC<='sxܔ"dA\YY돹7HON1&S릈7'1^-G=4FOag7Ÿ^NQ֮&@<8޵m,,tgCWy4i olycÙ7G}f`ddX_% ioW?>7@ 0 9~&w[_¼XAWe"tS@:wA_g {`rnDTjI._VG$ 6pQY{{%ZP{Dh ^=/\T/h.f\YCAkG9˚a?6Tjʳ>!u_FӜ3J{K -]IΌG1=Qф7W(MԔq~.`/ ۴xsFw֤MoxB8'u9R5CRۯM jk86j? MiSy yZ~9 4Hj N(~IYl b o诈3p.1RF>ݘ:8W9 ͟x?r~>@:ptYy /Op |W.dq.y> sȻq3XY8wNUsЈ1!H0 Ռ'>b3#z'Qt ˯eUֽ@D6I/ҹ"_5!?d,r?pjFI BQC<'Q:=NလQo)#,i1aа:X9^3&?:G-ؔ: (Jƞ c4;g9Zw 콇 %e/(WN$Z,_7?Fx2^HD+L1UCпHG(=G9JaǧQka#vMNB{W(^aw 0!ˬdKDI NԀ?{U"ȭ bgVȋ(ݣaWǙE/JM? U:ՙŇ`\ځSa۪%ܹ spzR(6МlU)ԄSIKK8?H|'gv 4NFe !b誹apKOi"$dP0Z챋2dL)vJOr˔O: 9pgA0=܉-3g'6ssD#}Eus|9!w )TrrnE:VLsc'tX2iۅ#@snJYD./R_o\i(:+cJZ:sV~aqxbUwOY׆3sͬE+wzA Y.)-ryzS-&%{pՑO۩?S/ƫf.Z.l e;`m+<o4R{R{s@6z_,UE=C4; |G ,8v5äbl^`XKPsl{NA ݓriT~M%=z5߫\i7 Z|GFQ%23Q+tjzBhp`f3"_\ GmZ428NZ'8OSb#(O[3$ ~ΞE;\ :YC_pd, eĨUZ夃|݌b1F4Xh\N}g"€> e+ kąɟ+!r >Ss |Ԉ`(6׊5_X]U{ݳpsa%*>x* Hkt~-iR OF+s4G8]g”N7T/7{ `N0tDӝjM̀66lN r \|# p~@ac`kL wgG[y4psxM=N 1L`k&^1r<1g5< Qu>~*S#q靹(\S}"[jj**I cf`R/XTte/1FʽI>%~qIyjArx?+O,Es1ww˺~p>Sy w+|HH6e^%WtmE%O9]?IŹy:9@}SNa{8I<_E1j&zqчoTɮOsR$z rf#ŽMX~T{ԖcuvϤlƩwpg{ ,F낕^ ˜ "N&P#Rp'籗ygp L)Ko7yy_#{Mԓ Cܵ 5{/}$B0bWWH ޕ7=:_lh/nRr9..s:eѥx7AsؠꡌfPdvui]cw[TC;`;y I2=)/]."+ i 3 Wsa>,D~M`L16v1p$nQű+E9)><!A0Fģq޾KLRE3̪1OfOɟSNخ"Iҍrc( f棬(4^Ay.>:Qσ7Ht)jk/r6qAF};,W.>lC(J#n]s[Tô׍g මxl4PG: yffӰ0vf4P "RRzՏf{wY:>Ry&Jl̷ߣb}~'R!.H/VOzuӳȷzwgPcTZ!>SAݚ^䱎NƙS}3C.=|3h_8TC/MWJJOf'5!xڇ6q|hbf7XćK򬟙-n&Լj-%ZIl+̴~wYf%~#K`srWsgUVW d9bkƑ8I3GYZ2[%w9®d_44"D‚tocHJJC˶#_y'PL-f(K70kCS$8Dxn<\H!e>kiNB즷^y#~]4>/TcO: $DKŀL|}bqidrC)E)Sr (tsm|357,βd[ou zJZ7L=YG1i!hӥ]xdƱ'O ND;c%˒doUiKO6E{-T(  ̳<4sUV]ơl7;ҡB)ՠĐq>8|22ZҦ܇J9 :}Ϙm@ U`ǒ^,l*}_gkFے+4G,ƥeNShi-^#ݵa}H2""4t]Z>!'{) m&Rg_4*XLƔa3<>ڡ&{/ +mY4ePXa txtYB=l%ZƭϒiP bLV"IB`-'wmkn==$Y!nGiFx:2~vY]Nh +W,5Gl)#9@ :7\&,uC El@|lFMY Hq_Mm "+2v0 SkpY*U$-ZHD~%ڌ:͚:R(pE%)֙$qb'%]'o{oDۊBqN.O\wk6ugI;Wz7xs+m}g/D\ُJW )Jҭg| l &{veל[Em.SksqSy~l43s Ut98cT|s˯ְqڦI̅ϵL\BP58|Yh s197 !\EBF5ħ%,71O lrlPE|m K]~ey4f=?|;uEB)e 7Y*[r u Rs`N' :*dG}$%.71Q Y";T5F#,et'&8tYi+%swSU*r@-Uә$].4*#(vm12RѥN 4)(56 V)|jKc'&=/sdM; GNt3Y<{,AX5Tgƭ7K f:P{CXb,y D٣:v"(sǵhKS m(+d58wG;~} WKnuMO+]8l?,'#UԨYZgZ@{ZVT{?7sLAh8 aqL ݒeM(,`* @Ț t36^Jeϫi4>r*H/e))ݡ<>[/(5mk#.]:ѡ $趪 Wx͚Ǚ[,8L!zچolu#qZ )gFHnU!ϤϩVƊ_u9:Lz \!W%ayqí@dEc6S[8d`Typԯ؏. ׼.%۝0 ?W/P+3!"/E[#)1b:@v/&2 _uƨT.xU,{F|oA:'| u$m޷)蜻ȃ;g; ~$o;Jf㙟4@k,sS5ߴbšO\= 6nJ{snn~^<@qNە^vSN7yrgQ$'K#^ %VdKXKQ5`6+L9'bY~B]'SPa7r q oYz$CkvL;Yɰ!*vkvVЀj6Dm&աEYg,9HΠZ!QOe,J@w*z̓mBT{p/1p`x0v d䟩pڧWFNi0?Nˆ{͑9n:kx #ӟ<8_ y!ta:Zm߀ <O텹'E!*Z*{V|u N;adWx{,T0Yz`V̍:lv{CȱcH\[Wxkva|9&ܲE6u AHuLh/F;m9@jâR lź#oFjvYtCa"0{u&7nt!$)X0f,0!Jd2.jV6$蘒;i[;σVXl7{V\H9SRT@25ǛI/Wz// -×歗D\q^OtsηJ 叓g˗%bNfEa*8yr̘9s CS.yAe!s1o2w7{4#m9i{ QeӔG㥩?c@X4-Ff% -hv;`@6DDr)^O@R ]ᅨ(jg.Mk[7=CJQ5:\"8̑HW~zWmtq)*=ԊO!A{~>a.Pft C6 BօU6u3x3o7 cB)'%#=s G:{;SP#4dQ2s16'ulb/kʼn<n:S :'?϶ED1o+oY43}XH&lٶ^8lKd6d6E<)_Kfuj+2evp7ș#/<+(h}|]E=LKCS]4ot0!" Smzõ%%[3i Eq$)!#-uxx*!c.;DZx~ԕ%c|EN8QB%^A[_.\Ցc%WjFERaˑ¸lr^[ X?kjj%!Kg|0X @tR,d5qaEgFW4wLz7&97":RzvgHvb)CBBubc,<֚(E`1kz&e=Rйjgʇ8j˜jo4^j^ƽm͡p "\Mo9Fض9RW-pVGܚF`ߧƺRK-9zүwY'Spy'YSdcs1/rȏ%<-2eֺۮώ[ 9Q3uqc6sgjfbsq[Eyv9MW:w62u9V"fT^ C9wg!RMm/lh-&c ݋,¶h^(Vy|QAYD^š67sUزEJ5[۷ȻP@̲qxqtyN}_}t/=yjGͣf~."ZÛf/O;T H| hۢ6D/PY2Tˡ. ,l f 8@5&D̎ c*(| / W1rɖ~ev0bY,ݽ||7Vޤm"ܧmѓՑ\У`&&J7ߔԁ8@0bbD2t n5OFi qX֨]ÒNCw+mrǯudD7?]PKZa8K]܍ y1Mduf;vvC(U͎Ah=!D\S7Dݒ)=XO=EyT, o=<9E'к\-0N jlYbE"#4sGl:DD>8@9~BJ_ =?uŘv߿_pV=9u8aq[=w;!`ѮE=L~HۏbLa6oB jRRg/f $3=_}dɜR)p׺OC0ŤtLV՜iПW Aπ:uzv)nN* -Xx?*j֖yy'b㟞mzjbT"7w[M~|^j׊[i" 1;KK]aa_l< ^4e2LC~zC\ yLy=f3@ }7LG $$,MF)(LI L:Q« uV꿮- ) z/\+-RAoxvʥ[ +^YBwĢ԰MCX"e:jGc88&qeق(o 5N%aGt%>qz Njnj_ݜ9~UMWX88`ꬷQ7ioUqu/}rgxt6JMJ] * {E `UXUk2t EZ\Nqq AgEFBg)š{:Y\p4 (mas[Xԭi|րslc},2Va`(G\qwE9Px$ƁRXU7z.RL6LZI[#aSdj"a u-CQYκnO6@(v98ݰrWzgQE`gܗKgEmBjZH50Y)kZJ `SM4zM l)@)% Եmc å ݛciWj&kGm_(I ZeqԵ7hA+9ȫBc̘Θv5gAg#J^xnoz-ވsބt6~׬J?TFtJaiAФF0֟Ue@XBHx΄N3龪wOux_XʹP>&@{wi%)腽[G.B jpkVGXf G>k$?k2EwwǸ[U 'y3b|,:Б@9mz-_?FIT[sy?\xzq*{S. Ld(!v ec,v\^cvy,E HR46I:)]^+mb .xJI-nU#,mY r< -U<GEdm__|Bo]_S+r~uPfr_?B7)κHu}7 ˲<0"mi7rm]YᑢWg~$:"+_z zUvBxA6T՗ yĥϬc/'{[S?h_Z_G82krCrkTǛ ]ɾ hK:Q$\0{kdWv4 >_#.Pӭ$/,,3۸_Lk-޻\8ןO c%$ۤ90|:]U_dQt/c׺뽐-bݴ_, *jk-aLQ'5KD;rW.2O] hBfDGRw8jma;a[SVEWB1hVqBSWnR RrL<0`lmK_Tk"y>UkbhB"G1,G2 AYݰ(3v"#VzP d+Qv69 t"Ӥ[|lśB;l }Ť !n=gD3my ֦݉%@kbaӉ%SqJN>ix0 [,cY:b1;?*}ԢYtnWX*Aãր_^db iHbw~8.: #˸ J;lcq#((Fr/Yr[)yV;Ǖ㊴0BҲĩBt҄0n #3`J4v=fMrO$G9$L{~,^ Q1AkBX?Y~߀+#|\ W8}el <|KA,J-w |¦=r8nޫ Ձ 8pll7[Bf&u\PT&;05_cO3'N| k h@mЃJ|bb4SLx/‚MV/~ J]R ctSK:mM9Jf(Ǧysߏx m5{nʏx};)Y<9h0H'lPV4j]ڀ]uܲ` ꖥ݊Hkm[)e{Wa!푝?kuZKjla;/I@E舲!#GM`1""P3IrA a:4an.ގ Mlp,jGo2%AMeB4D)`>f*c.W߈ަ}8:S{CkO7N&\׬X]cX 񎏫2\[\i9oeZn̵>U }8>xqN gz J(pGً2`S.#IutLq*G+%~jMQGX{Ss_3 {kS( k+3[ ;.Χ9՘G3q ;,f#v4CJ_[r4LIE:`X^pM_:&_+آW`}yHC%?ndW.tS1stƌ{ e(ցP}ku,]72$[OypWooL|Ab>\gg7x2a o {{ ߠ(0XP!g ^{:G5aXkF蟋Wmlàaoaٳ 3vvv6n2 Z##j'p=41:mي-J{A⁖6H>T~k# c:&=xu'F<0_ ЎRr8[s1b,Jd77rωppqr 03&-0r88 a\c*9#*~|(:2bՂ E`Zܪ$V1+LNFCgz(p35Q'vs1)T^1CfAK#n|'V"㦪2̄!+6VMS664O3k_$qaposo?i-pj+7h#er-dzpfׄO]I8D.A =V2-P5&1m2vIkI>jH>K2犄L mu7֫s' Q 4EI( dvq >C∤4,g p $4HF/2:?mo֏) 94tF@3dF%ծfEkUKnfADN4R oB[u[f9Z+Cy%D_G74xFc/?Gз0,J ><)o󖱳B'uq]'r8" ؃pz{/'91Dq}TxԧIOxLXV;S/^mhk ^3:8[%|'7I=q\4~!X#)Mzo׎9K&͆&q k a١zeSQ A QPv~XwʛCg(f[~Cj:}Xp?nJԄ֍Yce0sdTL]莅H#@Ԧ)&#af7eȇR.ǽ޹*yt~DsOI̜sJ{cD淌@x Qt*(:;q7KnY԰g001zQh2X8Us&f)Lб@Fafچ0zFHV&n=4ֶOV :|]߶k_ 44[wᘞ+؃G+nhSJ1%v&)\uAkB2ެji=\/2| Bp? ,L,ֻ<6lwZc0Qh"(O4^bl ؃e2USLp4AMmF+rvй&#~V.V #Ct J6ި?-\ԺPW_rȱ.l+CmAlegR5ͧo5号Kz&M}[m?F/Ui=(+̮摭i;95vLi'Or /B{L6z ] 7A'A~O ТAתI_|0yqIʜS1Wl֭1P[$c'#KЈMiIvA&dƺkVų{]Ec {9yբM;ynw:1/41;#\ZUu1Iد ͷ5lx1֥`OcaؔCY1 Ϙ1g 4zhTt9]w9be+h\H@'D 2b6a}5,F~<|jU [ '0PE5yб~ zc"@0]2S8."09YXz}Ϡ=<^8 th[rl\[07\gĪY aj~ũZ5}M_)+U5:>iZYĜ#u2>F3shFF_"CeCA-A[Y^7Qh._,.N.Rݟ'ӓ=hV oknkrp dHY]pKo%@8I2^0,HY?xg8Q3b߳u>Nq֯/WEisޓW9wE-qP`طpOb3T}ZwͲ6 l;(-X{Ǜ~Qjg TNߔcc̳V."ח eI|ۋpâ # ojzR?0p,šS(d#$moO=kX;3-D*^U3KײDEy$ǗSEd,]; Jщ}[Ի^b]6dh~~pjZ{%NnEudQ.g=~?&e@&]FD9<:t5#nJp R\ah{یzԉ'}uC+N*@u*^[ҦI&•xd#\;9zJnuqҶ汎cx~9K^#ebwc1;wb``X")ǿ,PSw.DcI[eT+@(E/C @MHui赬 o}ka3 S5.8FDi.%V'e<_ٱsz s-ѫڸdxB̳@9' ףf@hQp\glx,Y3}X/cdRLӥ =$Ј u&a'+ϲG/&rR(|ٙ^w} C'c4A)7gkK 8+cH՘Eߒv~dPQ'8_DiB8j٣0r!gb Dk|yzi̱\1;٥B-Rρ:_kkOh=7:*n|wӋWYZ%*fWA9g;]r0] /5?bǭW&z1~{6yRHp8YҸTW~#b8>=_P_,,qv %l&b\懄 mFLc,0t8Ru8y0mG46N@!dJ'PBlqҋa6RHs9u _&9͋Ww\a.p>?΂og2(kϷPq14Wvw앲8.&J4)ҏ~TJ$g6뿃0t ;Sk3}&<6r(\J8WQJ<)吘+d}h# J|&zwpt3BꈘȌqT8uP-ss(Pڵ2rߙz%Q0$ bY\ΪߒU4=j&4áJA\x]C4")z}z݆6v=IO0bkD~p,cGN p6qc-B#Gh1ʍ,]zmx'E;Ѕ+̬ٜPQod]Rz<`@4aㆵuoӰ>ąnrlJ}?\ӏVyIXE}Se9A*aW7Mm?d9 z?J([@0_E0(ԅX><5f6)桜aMdWfZBA&I GDע7o YAX$I`LǙvks k-+K"Qq~OEA BGiJ4,Gq(H*JOxZ=WW=< NXD9J!w:.`i?eAFe JF˺:X[hgNJh-VAd3ȭ}.&965Br/3LOBfz.]JzwÀ;ӷE^5>'ドѰ@qf絃z8'*V6koOj9eLu6F6 ZNZ,-6%eܣoPssuZ>XO9TftΎ8==`PWQ@tx搯$ݶnn  51j!r7Y"z2T )fz! $s[a7x3˾Sh¸ԋS높RyRAN}fݸ  He;z A= Jfȴ6'KI^I$W\Ik56>߆4--ۨA/p&m@ a4|:uVT%wzc.&V5 ^b)AhogOSABnxySKPd/oƉ;s Ѷ4s?*_EN;z(Ec}_(Yܠb}P-g(b3BۘN( N*{~%W\xP.D&Ng4.9%V!;d.+ 5}@s38 -Q}Wg-;l=/.#9iJGB>G77J&?=ʼn2\ىd/؄%(5QekūLj,PGj ڶ2dhr}t`HG";0Ec'^;{md_e,Mk1ezځ{_`SJKB.[`tuڿ__@v?u9=t"e;B~2꓾8veaـ&Ee!M,އI/43IAQ1->+qeeny[*H5h`J8k([k,hRʈUwzADǕ D1V6R B[wPghvFv)f7wZ-Q{{L7#A XadOyeb@T'L&,LXAEZ变"zck2{wn9#'x~MA4+ J9dWéi b"^&sNЧ6r/ӷsf-OXjѦa"0%RiqS)ω˜YgF8^É_DbZ*Zf ;̠*.mO1r~t~)/pO[a!-uDf{M:^Xq\ O`)? q9&8;Lpkwݜ}n9ѥVT/a'~#" K3ccK6q=50&2ԛc$vm^e8oW]qt;nl/5yF˂Dߜmm19t$QhWT-5V{񱔅 ۔hJ~/=!zpZvZh̨4Fnn@QO:Bj߄Ղ.&JE%XzŢ>%"mVṖ!P*h}7떝n+tJ=4ivE )H#d aL筨`K7p.ҒQ"5oq &IȪҔEx ZGS贃 & G_ u,Y[v5#,XѦ ъnwG?Rz) V%`=~"2#Q@CMA2W]%/O׵/x}YG;vEtL*8`G%*`on+_1φXfuRg*;qKbjΘ4L_ ImL~?oڒmc(f<"#num ^{FlD~@6'vМ>Xo n>S*|YceZO[u{}z& OU*_svh?>68t3'4`ٰK-l&ǯž0>Tqn o'vʧ6Nyh/k@?6N" \^Rȸ<5 E-qP;t\5P"Jdws7AV iX]f#V%Fwsg\ىi6RDtoiwr֪xthS G,kcȐlDlہu}7D|:ZCܕ,چVegiŚi`p܃6,մ*іUEm,vK?iN<&,_?BAߌfUۄ1卽Vٔ Ĉ(9qky]. ቖH)2!bd _Œr3 {,C D0LܐC<^X6)>>LREȊV7M\4#0 \ʤBá`ǟ-_A΍ݤ0\t5|> ^M'MS4yu y)!eb6F'?[sqX>!֮j~(IG׏Q5d:Lf3 \j7īz f3HrrCᆵjyAGOfEfW篲~ҙ~8xRz#Jm,U;ʅ۹#%5YMbB/RTǀB Qgaw$;l-j,?mH5]}gzXxSKK.jF"o +9L5;l9:5ZK|]铃}cǖ(!V5njO 1A?l Lkh*W Z{.e \˨K(}gYrs%}@! @Bax[-6Hf"< u=B#?S!11xgO^D1e=r9%a6[A6#߲܇fo` SA?笾rRF?S6|֞co;;2c˛(A٠3@f>jv!s:Ĥl+wB3!/JXnW98HXdji~Ee|#if3Zvz?I!} pHMه́oqG1G\%c0x\g9a:s[S$upnQB^ic*ok]&O`4\'.%1al [77EL2-/Jҏ1Q ieK_.okShfenBaW(G"\xY~,C+z^n zAw߆9G09ƫ=N 0 eRBK¡so9Kbۄz/[ iHY fk8N,U)3tl :vmR!jKx-zShشdɏDy7<Ɯ8aV. PX1ѱBg3ƌ\"Y ѲEx?,羉~Ⱦ3r.?`v!q^q'ķwq(Fk9twZ,4'X}N:'`tA}y,\K݁KPe+rʐ3 uCB"7eP=ގj=`H26ҍk`xS}xήz r'7 ~H;|r4~v ') uy? 1/ӝGCU$Uk>r#_Dϯ%8k g>dj~| aX}xm8fMoܐ(l1 =Ky*1~LLyy<"FfD[ʯА9@tr8q(]˄v3B 7m"ΓqHZ<9Z^S6T׮_7%ˠct ρ_Wdb-$ywCt)SpC|olRÙ~ 5`I'D9Vt |f#h`p7R;@$MBgm9ͣ& F"KVA;;Kq)GnӧE'l/zWw?UMF8oL)mr?~{whrŲypnj$ZaL}Ui ̼WyïB!vz5w@%/z_些j:0+Mid#qԇ pO.%OgsNy]ӹxՐ x z. ,JxiD!#fʙ=@>/1Ϻ`E<,Y4sR*PxBPS*t|Pٽ*M ^|-"Dm25*K\Uk j$c3 \>sfzꦺ7#w?Mhqx>jz-$h֎SՏuZvFRͣ[ s|э8CxJT;+)su-7;x# [8KN&#65S VonКc4MZ,k.Kfu?>[CE^|I44hkVl΢0{+;C\h?J asXB[:͠ L80ldDu3udHp -G^Hj7W(Zy Wl~7L6"`#Gj 9E|<+U},q!1Au9lN 6|ףG}'qF1sjݏ#/Zяu}iYm<աKso)`nR>^^q5@SO߲;,_46+&6/fєO_Nshf;s`2giъLtd;<̪cm`3ҕK8Q 1֗n97 3LEqwNv\jWzfÅ8c4UGHM멁7,>t}x ~OπJ~Kj@N?s{2ynVs]`Jgsz\w1IتmOs9W~,IvOYf1r3}1gpUG%_hxX|‚Ұ6fL6;O.{<@  >Wg|Yc(7€<_UJ[5O}ѵ9,GZ[H]slVufgb9%rR ;$IK6=@bp{%eqK68dž&KsէEF~jG!Q]΂(̋e9m(ϗ{PZ4tRr](/j=9Vgޯ! }c͌.JHcj$J dCYA#Ws1~IPHy3̻ _U*,-&69#K:X P @tO>=1;O7@Dt8JjcFU<#Ɣ}Ɨm|uq8\x=:QIׂ>!q Pv 3cmۚ# D'f x),X #=TzW5+]e Ìkr < 63l_:rɉkMѷ0t1zLj[l&Bs4IRo q"~Tti7:uHsw* H} &Д(2Y4qA'a3GGڒZ_[-̆iM&7 Eh^4q]Dc.p~ rEm}h'Gl%3!|NBހ;=¶a „A,5k/i ڐ08`s91Q)S),w7W4-iأA2l-kk$jչ\nG.޴zpX_k-~^v( 4{:BAum[~ 5F*$ F)Lz<4H b7H݅YE /.2LIb"mIHBtXϲ=}q0]wk\ jIaUrs2l֍j]τo ð&z)!z8UzR rz)nƩOz4+0(jŢNwS_YuEٖH,"p^eׁ0-8ۣ|Ph/ڨA0XCZZj-`,}] qíB/{Y ZpQ?C X"(q:e.d Ut-$1E)3GZ $P5̂B qBՌ7W[u&aQ'lXҩ?M{=iBd>,@ ,~{띴 t|r,V ՘=o4]5d|ee#C|?i{}h ѨED޴ F;| >e_>GN-_@sƬL B%.GqM ~'Cd8uR*'df#"ec%e;0(hɲki+,Dt% !ش4(d?bY뜕ٹ I륤*HgBkxSǢZ!VƀOV#FW!e. uw0з1`N9.2M\ kǸ38Ɛ-FܤU5$cHR׳yQGx^w)s2Ъ'VO3uro/°$ѡsnհx)VKq5_`_xׅ ;ctNr1gg_cУ&|%3kfkL5_|ƒr0^cnC3H48a0OrkztƸ+ +pgzSW7fB-z^ (19V^~{PM-3G1eaO+2Zl%.i rc;EڪxE?UO%`4$)0$Uo[|bHI(,}U^%/ `&Jo b $V}LU RrZwXiuT3S 7FLA>aHb`R$1gS==!ޗըh]46( X8 Z4|zҕpַ*xRF=޺1մy jB3al+(%evZ 2[FRV{؍3ެ%vB:8aU鐚ddMB(kO*: w[gHܟH6 BĆ)1z;@=w8k=cp qyb}rJSF5RvPpS2x"YL3Hs9-0Q3*7#;M/0>YpZEz9OԙNf11?ux G}M}vd#>%ކI;n8_'J?yd` q^1Y%9Q+cIDy3)nׅ`n`K (^;1)R=Y:Wi+WZF:}$w/Lק28mE@f 64 <&wGd*h$?xj;$Hcx*D5š 7pgEBo2atݏw7Y  Mm<@zӐeC׾e ښno֠[ s+znNvR[rTw:nֻv ).AI*'ZBKXB\%|>i^Qɕ㜣 ?_C6H#>k ֧n)Hx5[`C|?͍A۞-Fޓ[1'c&rW3CiyD# U_{"wy.Qna%^32fFUͨ1>F>oa;TzL{W_k66̳% &ׯ鼭`KiBev>@-L(6EHI,m~0ܽBYp% =Ҡ ݎqM)׀EGaCZO/)]K~p@ R^",x= :4Cӡ+beX/~\Sj5n5@k#C72H+n؆T- O8ĘfSn f''\()h2` D(ȫ AR)Jm ȸh|Q4ij7S"Ւ6dtjxYzfw"QgjB)jLC>VBwADa)!/ f;(<גDzDqKW&|W_Z8er~&.fzѵLu_.\s) V1.yIP/eE\rx!XGƼ7׶KiӍ֤$g.>KsBQJDJ4ݪcf AUV "ֽK{EN*`J E2 nBQյ`;[ḸXb}j̳-i.Z{3~xں~n PNs GY0U_AbioIT7z<(Q tD(:vYlLgXĜQ 2@gaځ2g)zjty8 ސG풥<*F$9IoV6 rkJ=O}ɢg{)I(%Oq/S4+|5(vW|v HHœcd2V~jc$l6uvd&L qln>Ҏ\S /gԜ71is WR!0! UJSpt[K]=D27GfEo\ < ,pWuy?b! %\!onP } I}~v=&4`3_<>.Ba4>=/rկinbg1>a:'ʉ##]h`P6`ݹ1h*ˤnaGŌn!x 8u ǝ <ެgb+1׋Q)bl1cD{'io R9/F87q(-`i.ԸPicL*w5*V0VUFt'c2ڇa 7;g n.r'4?0KSOhd eEXk3zfB8_a_yick A%w1K!eZ5 I82رX~7R 7p-ά4vixZm kq}´@ n3I=Ԍ%[`R®FCfU|Rc،څu1mpԻb'G't dwɎp65`!1G'%bQ E3C݀JHϩ v}_5M4y=?T!#a /A=B@tpVQ*r~[6`5' ʖxNXN|BYV?9.B+͂Fmf3&799lHJ圊 a0trV.㟋khbҁ+%mWNa;J+"eQ#BԒpr)^}+8y51unLm=2u<̒}]_ܤD0$߃VAPZ)}-}dd}Ʈ?R;?/KpHX=.O64-a߽^ 7L%??~^V9/J>+yF'NZ9xKiީ0G4A[~x>3r(gۛuDN[d/qCjvv[,A(SڴVS֢ }W# b(f0=6ɱY KmpR٬Y'i>O=YT^ZY}aGM,)7"dbj~#-1G0YvZb3ccy@pLot=] 8J9z}5/>1U0蜬PH~anvuB[s4uꥁ$=(#[>p6| $&YZgaSқ-Åh;kҬ~gHU /!K|z s#Z ?Z~!~>>HLx57g7koPg%Z)kOL 1<29h:goEre;LJe,}]n{~[}[2%Fw_KM @ )x4-Sg-pb?oyS?r/o%t^uscA%V`9zU] ՗')j$J^[ނZbv{b SL 4S8k~ \)UnVx"qYL ¡z~\tZ(3zP O5 i=X]b/Un }Үk~ʼ04|D]zbXn"2:!|jЃpЦȈ"E\Yn; 'sA@Y=9Mr7& S#>Lנk К|]`g@ZZ8=(bkVQ#`i-L,62E7a[.iO "O G 0oa9Ames} Yu)GӺ/t3ݔ&jMKj?b$>avf6*0x:_q^};ZOJ/t$frb#^w/Tl "8Ias(BK`,jQuQߨEeI|܏3]~[LE)#Ũ戦FNT8I܀s=Չ# v VDىwE՗uF_7Y'~ڿ?X"u?ĘN.CrmzA6f!px2aTLܧ& RgʧM2O2fтvMj䦸7qF*4l&ɦz'FuÖTFza32ʆ]miRAߐ)DZ&\GYkވY71K!Dv;'+ISpsw9K6E^$U ky# & Yo&ڍAl)85aF)ugG=P̚Fh ќ: L* ɳWP3yG28upE{ޣhhQM0z-h iQ@ʼn{p!opƌQq3*ׯP.XIV̰yȒ`(0>Y (?,` hDrQ !xbaaYn'5/~l hU\Ϊ+O1vS& IiҟAC#9ds՜9k1kٴe5IDNf#t B/A,18iɖ_^3KQQ XVF)92,/ `q-&;=nIѐ#Os]IBb&[ BЮvRi9Ѣ|hrq;S2 [`5c2(b'v^jeB3I8q0s8 ä9pj/Y m)* feMΎK|_p/*'mxDS[2ߟDaάpprʅN"3y1y~.}ן"?)V}:q,FaMRx؉7q_Z̰~>ƹRʁ}_;H;('<^pie/}P䍣R\=mf2o%belu* G >H ky8?/È35Ej_sGkw4 Wsgf`]ԙU(i Գct5pZX8 <~-.~f˲k#o͖9eW{>ж]Z`0@]hFr9YMY q1nb 7ܥoOpQ)4y1%P\KaVjߺf]yya#Ncޮb_,e2vU (+Wj}u{ez )l5Xl[Ø4~9%ҰW$b2<,7i3P+{ʂN6`{7镥LwNzo`^3#njljr`o%oe+ FǧbPk%7XՎJXB֮ agx CݳńݰmqNg6X@I?vZD5B4^㺻gE.oF|K{3߄ %j@F& Gxh8w:#Ikd\r@ " ci^Eݑ%qc@_\8ppg hf˜E07+ m2# 9=ѩ&ɖ3ǵ\}ɡsТHO5Q@uհz,>.5l++E[n,|NM`W괋%zcm g=c}q l64/kN蚗G `:_: 1nF"ñz8-ݙ8۟qC|TqfJ3<F nye0#g͎}Kʣhs*q&YA^3=xGH=VǕGϿP5́"9ߘ9pkxgj8Ur5YO}.1ԀިP=# 'E"bgK&E-e E#sDOG$a8?RS]f`&tcrV,ӫяI=)LrhД;#[F1ŒBrm`!5}#]|u_Q)~ W HñMrY_ TpnSӈS;i9zNx3 kJSee_}_ I.}0֩E68ڛ Q'&FMOZ9V .;G&&O kwo*~g10Цow%y}6"ɻ5Ēt R(:h2ԁh :/u`cߜch/t{%/5sc]PZVh`OҐi |[=TBCOi`J.̉=ї]0O(ebT3BpW}G}0wBCä +RX_dօaJ~As}K*gwc>t¼٣J?uӾA+?KF~fa<'4zq%Ìٽ F~%PD[7 k?.:41a}x˯TMV)N}6"юu܅%/}TZ6n ^#wP4Z3>f,ؗ dഘU}ZgXwo9W#Qζuw#r+O8:q S\y6}*ZV-/ѸSv`Z?e*nqk^w!;a0ɮW/ ^Wt(*4H5 31K%dnzˡkŃ|&+ҒJKs3V8SefDksc2F,MBN!u=ȅ\0" ٗR0)'8V"o+/ z;f<~"`8317sH1`r21;;ZJ%7({ ʺ@ry\27eA8Zwx80"3SRP9117;2 Xp/4ǤVa|l4m"&΂Rt 3"zӟ} rY` t, tA%T9^4((cjL%8872'%uԞwCfSZ.K" CNM$ř-EK iWsW< aD[t JZ4w"m/*#"tMXq!qT+ m6hv>;# E1QkE)8|P^ЍVR)ڟ7W qCB$,ZX}^ܳ_rmڜbx=R]'gp\dJL^z_)Bq]OҊ.̝8 5bX4XMg w >H33{ϔel髏p0{1!#?AiOE Ok^/@~*H AV7@XY fG=CxTZ7RiM_bUMl6fjsͅkFGqcLk-gbͮ'{;ݸGEɝ ؽnh ]w]s[,ٔ+ Gk=yDF 3۷II S28JI?}>n^W %Uqj*RB%(*.0h[Z61ϴ y e>5cpgF3-`۫y̩轓 N4꒝.D[ڈq&X*Hp9WMpIowxnٿ*Ӛ{~F+"_ߏ?h9LcWmu֎Rkc@~_TBmXZD&Lǻ_bWB2\ %}Z1xU|k$Om ?νsLNPHĐAG.Z ]1@E (٦"NFpA3-h6 Lj,0]R6x&D8̻#5͒ hbɬzKVYRyoְ,9;$ F1h(FV[L=( u13&*LZp-!32]73BY}-gԌ59ځz8=L w4*RFc0fYa NiݛP0+Pn}Ӛs3a|9Y795T8Z@Kĵi'gaqi#B7]wl-.ݓzl_J[,o;AϦ.;݀~ƞMB,&TpǍo%,N9,/n&ّ[9RxHqC1v 'jzS%7Q<\kJY%vrX `$}Oo|w }J4G98b"o^ 6I*\+YYEH_bz\kuQzF52-yy]k,BK0Fe[%Y+L[U^ Ix≎&Ԟ4rMuDH$&XKf^X|0cMOg%kcw3-jU↴|qhu8gFG{][ KipN~%}''~;ֽ۫@eP]˧a#c:J%)%߁fym֐tXGb-ZѶs/ҏcӢgd+ 9̨Y7kOǷ"*\Ƶ` gKqe?.tN"Zҹ罞JX_2֭q4>AŊ߿<3<}j\6E7*Be㏍ga3+r>cJ5?8huA1R䏽gR<*d*KG:g7f(h+ɍ0/82U-|o B%aIlca_Y9x=լ4:q].[gqj9~K7_<_Bz4EY3mJsP+L rMo~X)ScB %[17"ڝf*':߱>П$LlZ%Sz>`*6)RI>4s75[\4E</Ϝoqoh%Ff/c\"o4ovL~eJlȖDrwZoH!J\cKc-Ѫ9HnjV4Fo(:L$;LBc[8ijXhU(P{_*z34WNG1]Л.Sa<$Mu =;,RWFY5Z(&=\Z QYUK]h*7;bw Uwטi@@M*l$%RAEfj{F wC~t.}rKͶ$3I7źzwEn>[j {KԾ<쾓&5įj7 d>svS}>/~Km~݈2;u~rM;L80''A7NSړ)ي#wC b)QKbylPz׸30G G*IRv;Gu`,&3>X=1gQbNIV>YgcoBpW;nj ħ=z”[VeQHx&hP&w!bD-[gQ'I3j 9uz~<(9^PIY*/@ 1LR<"`jt9cB42+mm\.Y6Nj GswEg?0 ̌@qGZ3)E A5B쾔ꥪ}Q3b#E"!PT%2LQ4;Wωw^f :SYS6d*tW9{r~Äd6 Ķ}e"?>o|RL[;Μ>bN_AKfiH f"ITMraNl-Po,aA09Ly iK r*59}41ot%8_燌wqmQTtk3zbb}2HuIl3O9hߤq[[lRbG3|LyeǙzn D4Iz*})_54võg!Lr8uںĮ%A^a?SH%Bx +:9,ӕ ]tBfjhj%HW\!.\XHl-[1/]蟔b?4QWYꃞmdh;7e+[o)4++r[\hwŒfri-_AS(zĭ-2[MyT Ob[YX}Wް҂XSMdVG ڢѪrCPLm3Ise17Ѝ ^M]4wUP~ϻպc㊙t@>Te+^aӔJsҊ~24ڇ&t? }1T_{I&IBM>t?G)KDɵ| Kqװ Q .oEt̙(7Y$U|**v62S 4/i6 26]@EK#hKS wSxefqd7WYf0_"@5EgJ0@7u* T@H`gG Qbdh- λy#IR:`cl_zx7v՘)%v9K4l/w5Ȇxq ٦lB]UB4:,^}]$mjzKG`ҕtrL\`ؘ". ] Uz I J-m#DDܠAinƎ 蕣EDrrGVfa[c4aYcsX@Ԟ R]*3>4n9KsJ:8m#C} ߀y`M v:Hj:1IF)\TG9^G/9h?8Z <@~d[NNY4Os^/3JpVz2r޴+gP!Ig_OzC>vsO۔ ݪyvHo:q{T7ӿ.dWd] t?sN~WTtЎogP eɫ))[za!UrͰOO1j'_W{usv7z{f0,*Tf^;~*sY)NT'[HA*ɰ\'˿ - =ӞpձX&ơ40zɥA#3# [kP&f@P7[A 'ZVAz[SN"+No:-TQ16x:F۝Y]b70lfM)ZyjaQ%*VΜ>4*ih q? 0z cM@fUό<޲ޢ(u&v1k_T&L>1_!pACNEׂEVPM\:]%peY,SOZś/0jCp;p[;)禒/Uo%8ZNY ܩe +ҒҎor8%~YaB m Y|42uB׌ VIGc̖IH?HPgI:هM0Z%-a4jC+և5J*&vTؠC0@me"(Mڣ55݌F{ m1z w G6_ۨTE~Ȣ~ w?>M3Ш_t2+rg\2y⹷؜нH%cI9o= sܴX%#ԇ=A\Y8Y~`m<f ƆYc%&?!ccxa6TJ%p5*2J g?XfCUӌO 9ړ0LNQ1 '<|sY FnVJ4NRE*Rp$t?c1х5ԥV_#: r?; 069Ֆ9ˉ=E(gZ~9_æ:Z%c۹!gn>(;l n # QW2'3Ѥ(*Dp^:UTl}4EDy1z[GI7"3j/p(MeCk^ZtQ(ArdGWiVo%mNUXmձfMB{P톔nRӻD~RZwt;&mF* >l%Gw2Gfދqe۳ u *zUPwwߑop BQpzgvjތ]& Iys'=Ķ<!%bxnF_'䄤dWа}|#>]0`'GiA[!:ml{X7|%q"͋׭?Y?fLgO {z+V_pndbݥ9Olz>ϨժfT'%[bPl&7}r>zLC{ʊZ-ke^4+"n~lQ`-sNDQM]",*fr{1SY+p2AI:%Rȟeޢ(c o TOliivSYbiE3A匶uSövq'dSw52͕!*k7u@Q\:\7@윕 Ȏ h wjVmۮ<`UY8ѹ<-VA+XW68TT.m8]8{:svN8h ̟e^9:P)5)oM՜*j  j>}~֓ɧQG$O]kl:LGݻTʕDu֜Aw[@ Js,XWHU=j=iE'f!!y*[3kDzSW-àwq10Hit)f#ngS=1E5LaW:=ݷ;d(NP9 {O2H S=nG3L V*UGэzWliA_S=R!:9W-6u}"u6T10˅&[rl7ai/uime=:YEfL^]O< tOk_!Plml/Ԥ[b6䖷g 6O?qZL6J>2%+囶3oeQ{nG5B2ԻTDvVSeY:tޔRގ4j)0wB8Vrk"*UZA0oRhh8OH? Gʤu𭁴LBHĺKY(d%Ʊb,V$P/gzN+ 4OP+u* YɄ~YXL-g6>SUVNx5̭QﻸiQ?{[QINItŠW 4vR:nÅ/$٪ e#>1ml4ܞ:hR 9sKA7*WVl"~&_E젍'g^]xOke(8IPp,W޼GmQ$V^s0/6SZC!4OΡ[P 3x.gQ0Ȋ|l>A}렦cf<U.21ܧyoD`3?xx6@׀V/XC x:3(ZYbvL?"c.Y*5@x.=TZly׈/ jC1o/[R'צ+q}̸IxvգwF":]\bXGks^)pog /ު&_Ol?]^fS|G&BJv_Կ ( 7#@lW"gܬ(eB%B Q1Z֦Yi9pҐPA07&C#KC)t;[@ڵK6 ] 83[Rm$c6o ;Z j'+4L{oo W5n7$6/3F6Dmt5 ̋E/N=T~^>C+Z eE9*'fx৖;Zӵ躁>M*ؙW+uSB6烽Í,kÜ73bi)L-muR;E{ #NaxޭDYUZra4蟗Nsh' ̑zucMuru% [4T.j"sբ+N̦w4;ugF]'U"CQPiD, y)bC<6BZ-΁['RPI}bPR1WJ dy 63qΌE~B\5كȸ(NčהLT8wLd-&>y`=sܸ; VDI6R"cH #sQb ċ1 pg(iw[a鬣td;^ Yٗb?PӐ]6 ޳~סP:T w Qv'ICQHGiQu$Zú`ȁFq|@jϣ6l'-MOe!ͻĔQ PƪS QK7*D4Lɾ>7 T.`D2bbL[&m{#3.tW5^.;m5S7 BW m-*@` @`вGmX'\ǭ߾y53yꬅUl&k 0^nпZ{Nʼxn;s ǐsKQ^ Ϯ>D +kētu0oY'΃>u,V{qϷbka.Q>#om9F|Jsr|N:ȿZ>$e!n]sb6E'[d}X p#tT7x4uXɷCVtʶGɜZƾJm%/|ûm^B?Af6 91!\TP. ,oh<}`{sEi;ϣFwxڀ& gU"BxDAFo0dz4C8͕d=WT0%ޔcbP҈r+O;pYǙ|NG:Wmf2E ViFչ)Į'.^#k2t)w֡$e4.$ s&m*~6LFԈlTI7u-ml&;@~`(j])2/3,z7/o"{r}Pu@6&>IW]/7AW(&sC ʩu8 ,7AN/ AYsLIћgmWQ9?+02ӸН/p\@VY t)7yˀs2q;\z3MB` tsoD]{Z%<ΟJe2_vz4l*~<'m Whj}A}0QbZ+^JA'|m \$[H P8R '+R}˔3A{`_85M5V*,Bb&GqTy̵Ρx^t~'$%c= ɘ,_:PƃWP_;b H,JU⻥3 :;``3qHw ; Mͨ48$y3"y=!Ԟqaj@&'RIށ|K_Yɞtآ8dtoģy};.oGdw=*t0G0"pM.v$8)zc :H.%(ۗ]#j4lZƍwQT%B59b2`< 1OߠC3wOtmyάΧܹ9ݼ&sK0PtY_55輲%l$meh2ɡ/$$s/mAo !<\>HoVi%mn{3*~(R)n_fj)`4 Lu$6mqOtA 6tBe A;7FW%x*u kr*~l0p՞"M c]Sm', g굘"Z|lŀ;(tb#]y .Z%ʣDKfB7<)k;sG+_-rnr 55 :[iSXd@=BCuZp;}kk+D h5(YSZaFjgM!FTdZXW[m}cb- @/ f#tWD}1d Cț 5iK ]}mãeE hV}҉ Jxq` 9D0 &u2n#r 52Fϙ)@Bp]U[8-Uն-}w`aLݍKXy-!By21 Re.%W4I; -B@[)zTw'FxW$VL0)')j?:8Z<p2tޮdxs?r\H"1 NC v/=BxVNźޤ^ 8ba[G{/Ebw9;[jКj ܏&GQN4ׄ&g{p7%ϥK.<݆+fh\NuG p?G2+IkOA̶#@$jfdV+#hN^*e eBgpH-I @UO_}n[䆜PjƁLif6jqC A(MQ[ӸrbN JӀSww~n"-GI0.q7AsZlvޣ)M`Q3p7 DӠۺK`vQRwLBX'X5&di4gُ0lYe0xe''qiU2qz}bfn k=T{GP^LCŋhb o=fU*`-#8Q֣O澇g@)h`6 9-5ON<(1u-lYڎ1Q: F+-s$\H vLzB<,$ ~hEczC~e Hܴ٦@T.Q|B8G枀U>$3l[nxjiKX;q@g$;1eT,hIj}1 MeX=Pn.TAXUWpPGHFAC0PT\׵bTh5V#x>,NNS9ݥ-ٕ-Tz dnE?Q6i앃P 5sw89El׋F 0fF;JU̮lAM:ݍ؁jg@kKD`uZ.v"f}7)3k"66 yp5(]sI;=̖;7FTszj k(5$ V\89\Z9psR-pX_~c!ի`^;\j5J.=ﯺY=)e:*ز EQbb"TiuhӜ̻T2{.Dq:,sF٦.79Vw>i2uB<϶ ?vf5VD(oS{Ed (7EfUt Z;*S߽1jHkHJVa;KIk%51M5MZtC5-mF l@526: g꣖$|7Mk)Eaښ,***e,GQXX@}]DI&r}Y]拥Ѽ":+w9͂YT$âced3%_sa.PxB{dJ2)snP j*;xe]Ʒ%б\n ^.CHkn꧚slqU14EIZv?"2TZ_~+Q/{᮲7є^␜bz6wV]PCa 7 &f3Eֵ/+wdqDX:}P GU/ cD9djpHCdσ؛xZԘ< l{0R>c8TfU᪬B21M)0hPͺoZfeij:9w%#B/Ĺԙ|)3-TȳiaW4l⣟N$dܘOk"|B79IRJkHǑUgH˜"|g;ܭƂg]YON< 꼚{KbUlI[yr.Binbt8ԕ/y4[yu⡽S/gH6F)ZEZ|E]Wcp׹pz![E9LM'USD >Eh5 c< oTbO~πY_mէ%p@cGNcZ R`IX7e &??Wm)q+5b.xw+(iwРy7`=Գ† 9$ b9w1Q#7_>7+z-EפD4k5ca%P4,#-*hImh a[h ͠,?aW1ެ 9B˼l? IP`ERgS͞)Be^h{S2ySKܧ+=' OP )A*-^@՝ e b*28*KF ԐBtTӇs!=%[O{4XT)ؚ} 3>-D̬ӳK57 K F;6?j-е6jhSwO.U v?7+uPiu-R^dDI:Y 2yQ館 JB׶G G_d[+2/ƛyO4IݒQ!]0kL`g; yAѹj'@L!M}VEĢ@EVh:4z_80zMceoBb:%=r|.Cc?VCMNF  Di⮳-˳IN? S3vC780l2 9@W2(%j='$E4~$&kB?LncOZ}QON@N_VL"l|aH(ޑObEJq}w#[2억5f\B΃$|s/ \[TPM!inNd֨| ZE3P 4pRj<7P9;ꔖd*A\tAVrW7m<7"IBaeU%@wJ\/4$,G/6ٖ˪jl7QD)q ~2Oc0$zFΪ ʒt rr46ޔ'Ǫp)x*iҴ]vH_=/7ڒMD,3LF>tE,v8܌Ej0ʊ5+.鏚|Qk"^lu[+1%@BΜ-MQ ovݲٱ 3Q}¶jS[м/4}(*[1Vy<"EqΉ= yd e$ eT(i}GFzv:HiYCW2b03,r ,Sܐ".04䚓*hkHlOJ등|d9D#!sbžuw݄f:w{3y Xm)85# 8 3xC}ԳL[ggޜ}o 7'5_ z1Μof }䯬h Z3|7 ޷BM'd["p0e /8~Y#3ܛtcYWùj#Q2+\ߊ͇iӤy _3}pj87i"Bv$Ǽ|uy] ClA; J.X.ZP`x!p^~! }ĝIKqM}OJHsGrW$22YؖBJ@fηo t+"bQ{F,e+:pp*`K|*ݺ'`j1ՑY2e$)w~ 3%+ý:X9ՙv*Yl jY7M4H%thIhohd%7ک6bNh[9"l B-ōc#qeTW"q.<߳m.8$x5rgzüxUP w0hb? S"}BI3͹: [ ]ZƦnZa ǃZɼ;ivH׳01JQZD[GOEBW&R@L2ԕ}?tfӼnKsd0O}"ZLgSI?;86Wg^i 5(Ȧe ShL8lSm֙f laJLd龩UFg 7Ho)"HDh&kvHO6Q}4^EIНҡڭ?r4?"Q릆@lnT1"25.m phquA;Ϩa5wrQ7ŀlT-cVІ (A8C7i'} eЊqj,7 wi (ʮqCW!LZ\|[H*Y_a !j_].+(8;ArX{1җdH^TR!*d[#iiec9׻}#c6^o["v e:A wa[S-Reϑbjx‰PzUK>E\ W!'+TVPlgPxM@t& KQoMZ}`(&xA]$CEcv uKP*DR'd4E9?s8nm[@WA!Fx4܃ AnlΎ[waMq&1l9[:NRm7,ds&dQv'Q=U(k gtq0M"U?FvR5ii 3W]qPѹЮqBc1y@t|Q~~0N2<އVLh">ŏ@{_9fQ@82z€۪8/v.b}֛K6:$_H8]:ϵW%*=d`Xl( ߘ˶j/li Zk4&]<=b"thgQoa:j'5rr JI(cQU"T}rz_a۫7 ܁_+KQމ3"l#zNb9[1=ug gz#!`}GhC fu,VnNFLdn\Z#ơUVm;)tЈ6 큘Yf3h낔-Ӓ5˓7Uv/ɂ6R1&׳oj 1G=Wur};#Pr8/}`{S/4K$ QrS3}W\uCcZ0a+.yq8Ɣۃ;wejRnK1;$\"Y.{AlCRǢ,PQN49mI_\-:7iZ\]v(` wOwgϛ_ UmXz\G<9\SoKY R 1ٗ9_4N5kbST"1ҳs I6~|(W;IQ;Um;ДKv*E_GB9jle2E6?oiqtHMbYΰK7R岠6-Lag6&Z P\7&~v0b|z&R+C'- IN̲dFފ dwEϙyɗ"|w1_Ueakd?zP`.DOJ"[]EPД=p21O dX,00Ir\(t?UnPyG0OF98:Կ5e>[JԞ3?vnr0n5@֧񬈋q8/a }[h TY)5šeDz>MWC؛^F*+bmޠ'E tM˭hbyUr,8Ph5c+ a Sv kޞ_šl=ocys^G4~bdѯAiLJ^mcޑ1I[hnXXOTWR[4,J(3} TOĈd~B f\IjF颶C3ove.K=з>Mĩ2JRGBlBDOB?})xTwDgc(QRQUj9tFM7[SWm\Ϛg Xq>s\ PkW>B84txm<'<[v˃}egCLEь؞_ AX:+PNU^hv4P_cNHP>wYՔ~lT껥hS&Q`c/}h+Vj~".3r| .-`8ydT~5>_ĕ? EoèmA)pP{g&μߢD &\)A5dRsKѴ~kE:Ӥћ!Ll\*k7fG'.yʼgG/dGPV@#0ՉxĜ۳cU3oRȱ z)񰰡RȦ. iy\%īp UP_0JQ] nFGYaMRKƲ!͑$/\ v? ֔0;~QI{UYl/\Q\ߧ01@һ(WmmodIJwyLʑ\z_:ti&l 8~cr>홿ʬ~v&+2bo=z\~w ~`qf'@㢺2Zھ;5ݴqB]?jŏšC,U"!Ύʍ%S ~LZUA>I_dKG85F0!iLbQ~*>06"m4/:ש$0- )oFl@MS>׺1w&n>6@uP~W}}dy 鯒0O,[~9wGi_q**Ki` >h'*/tw! "@;4TUirݺi7~k0fڳ 0x-U3:zPzw~-0RA+E6!ݠ"5@Mo> d E`/^-a"t(qNun9oC %kܿÈG2cm/FPZƪԔQ+ڂI@>ڧ+~+)I-J'["kB*O58I>-\$\e:qT1Z$5d|hSTF}Kݠٰx;YSr-m,Jzc2erBbh5b]W@;Qצ)S[V=+>UaTC* xӵ֜o9K:F}~FJĻfz!B8^B<]0>t䧫ߘɳ 6C8tma>sTm: ݵ㧜|w}ٲl!-g1I g9+/yf&1<JІL3qClp*Ph 6 G ܯXm-'+юrk2'lZ,:[1[Z:QQlHI- T4_yYxbNPBH@_pNf6OJCK]6z&ԆBg+0Y`8-u1g}C(BPḇ} |E9>E+Z>³CHаG!&RWV^R+%n0 ׋$$plX^OR2٨kZFLKc~mZQ5m=) JJB 3글+9sEk3b*4^֯dr&D{ U cU;+Kqq7^C cg{BKMCذApJi ͩ= hs΢%FZM}ZCot؄M\i%5/Ua؇h7,3]N(bϪ&{us,_,$SkwTE!㞗m@-[ WTHk?;ɚ- U.׵ܑFV <J4˪#t;wyUpn7;0R!53Ҫk@d Ii Xw-.a ̲I NHoǏ5Cƒ'i meLaZ^Rjwο3J˲X(18;m&Bm e( ٬ٔLr10g{籹oqкg =v0J*e3p-zrϬVvF+ݰX tGSU1:KYDn)ڞϐ&] SGZ(-$dmgJ7oZk5.R]r f}+$qCO'O/E8*yjˁ[.Vya; g糴peSKY=qڑ? ߨ8-ᔌBl@cnK4؂Er8mPq 5V=.?x|$}7WSztsVxRY` 3sgLr +ߏeSH/ݗhx7 /ȹ<_3 4,>}ϯ?RcuV iJAU~ VNx"?G&o`bj7Y*ѱs|mH;IxnJ0%A/Zpdyj\KPP: đ ؟oP556' 6f,]ֽԄE\ži;>(WƮ'(}uFU`@ f" &Qbn)A]ju[I0ZNBbӸ.6~G4EA&Yq( L2lĆJ!"f]w4F9zCwҏ^Tz!\.n<~1eN_c'@; ~Y쪬 ~\(():dX5c y: hiO7c OZru_D>HW(l,RI^ei3m̐^!kؐ+zz/dڎBl-V Slvεb2:? rMq!aQjW!{Z l՟γ/Mi]ЗF01qv <thy"eC&B9|]f7?;oQ`z1b>RA) qJ@ ?2"RSMZUFc^G$xA/굻,Ķ/ݦu5=f3~ԭ$DSrt Py4P:QHt[<3-rtԶEZW oʟknEڙQA<}yԱjzǍ#Ɠ{/gQ\> 5+ꈩ\Wndu*ZF(S9(;[83S[B+J~gD@5P風yP TLhO֝"He#nHz9Uj-rlFJA/gc[|msTD ! j%Xe&5>tMm,ooSC+6vcRDu6F]>֐V 4E4xQcAz ^6m jԩ=2>ySV5.x  yGld2@*üb\֭EHBl.>b_J#UyeDw^L^7%9J+"o wF``h wI$2EqeFފsQm{ùT{M 5hjrv9"e?&p^ˁ5Ͻ|&aϜêpFX[A5=HM-v'18 ! /Ⱥǹz7?.Kl b7C/*2HkSb:5XjA3r4_ܡno4lao ;Kd _Y|?'ZV(O36] WNEq|J5 <=);{mrdp-͏D>XL=,ڡ}S=:GVk{tZSS gy@ןYn+3G*LzE|o70 6մ' S>@ymȌhݎQ3UZ_lKVD!}@vSMh+сu(dꡪ8T-"D"+iu(;B{&Y7PÊ59hm6N۫=o=N7w"B:W @ Q\^P bm6]s?EQy~J <\b=\o_Z!Iro(IoqaM=` 5PSL7,iR&74E."J-ĐÜAf Q4$7ĈV9H N.=Υbj &v_MoUͫaP:'!] M0sʝ:,"tJbD|B~~=x/u~VxԆUrC+Ijϖ9{|Q3Vi|bĨ "[B$ᢏ³yW,p%Y⇜UW{])]sz[({M^ғ~t/u}Gez햤e⛐r+7 }RLDI)9NS|Zojf }JC]1[0mOPSvo]HaT;441 ;sHlVR  w yK'b4Cn 's%@}'mDx)a{EӦ[L/6C8̛MԞK<Ҕ(ͳaC\JHzs3h9Ý57_e \ eqo79WȹJREɷaYW`xѵgj ~kʮc^1Dǔ$l *X*7*gƧ;~7΀Hfkt릵I;9TTbN@J:00?ɜ"~>[k|bWg V6M[*FvB.b61T~$kEZyiRzV=- Mү e׾o##(Z,, :"elUdϺp uTZ&I.dkN5Vfrn;BD:1ug_fA[<dM$qvkh`C,htI9-M} RKn1jvs*Oy'CVZ-P+|"B6%hh)4|MT4 @Cy ގ>fg蹔֒5Yl*<ԎϗG|{PNNt)w&AOGﴝkJ!+Z'Ti y]AWFb~?BZBPy@DKʓ1Yqqg9^2{s d\+r(oq,3f'ogՖbZ[dٔ>X'8..b ~zdKK GZw\5KZ&xX͋d9q9aL/;e&)WѦA܋[x8_q?JE."\<6o#k2!2Yfo,_k2˭<ϯ|ڄNQ& l~X&t9?C,>Ypn hO;|/h+Fv (#R$na9+;9r4ێVtOhdm͖*JRUCRKhRmxˆ.޶d- a$ŝmfye~l~Bݙ{XچRMe!Ir.բ=2W8,GL+7?>tXmR u R_貎1xIJ1)zBMtWLֻ:H8%v0x$(++݈l ]Uո~}5fT/?5}U;`SV]>wZΊyǽӜXܑu׌9| HXD]o8o38Ƒ#@n8\dd\(+Xxؐ6킨.{LhI e~ d:aX# 8b*ZB5#v%1Ml<- GO6=NIGUw|kݞKњ.Bhު9=H?I={XBuUzW )qQLYؽsǪmN۔%Sω6pgaߘi{ɜKp7~xθQ8QDK6_S&Q)FOZa+>~((Mr"Z&3 dfg8/iҮ噩L/8ELҤoHLKD`2kg*UM~3l 8=g\1`Xz`CM)?/-=k@g5A6I;=C6Ls&M@{ 23@;Dt 8H~˖h 0jSWۜX{rj'UonjjH3 ;`5 {-Vvk/fQ!ՕguUN/ļ:y >ju#ϵ,A*yf]s?gyaY2(^w3r~J{!Ho nݰ?#܉OZJrbn f)0q)wڔ; ';?seҏpUB9 };';9C+p2^>D] ;~99ivfo/K*}<1ۮ)G\Hάk5i/Btjo $>b]QWS;c9;2D{'|3O?i?jfWljs=U, ->Q9N91e/-S ,_s)y.3]U$RIOr|*̞T\951žf@ *.dB5~lEb4| UqjLe$] ?}xnJmY[C< [Uj0:F:Ir^@( j`+ OECT3],2xFY]yUjYAg@D=s2E'̈g]LZqP#`S˲Rk|]s?|X79[(7fڼYKdͅ16YGVݡ٢䌼-ԍ,5Hࢫ?ROJ8Lي8*&O.ԑI!qϒ->n6>@\wtz{$.zj$~u͒(q#^a)z*ɭ37Sc'Q[Us% w7ToJ! ͊vHYzZ"6iB@rЭu(;4ЗRi?vefR::sdS:S.@vʞ]NM4h,M)!37}Y_;!Q M;끱Dh}X).b+x־Wk ľiEϠ|Z%sfdQMjEH p.KW;⅕*:`6~5~{p2MLML !yO"ET3O~1Xl8Au/ˈ:@s4ePm+tSn jJM"*=ii]E9kPD.;& M W2:汕bȑ?O4p_ EqN03l kZnhǖ|o4.ҊNk"=gXpVk7HzdᅟeVk1h< Н{i|M2!NI3n%ץF1Qb~mMI-uf_]hY'pGJi~y9@\TOB=tUREY~!$Ji?;숪)v?h{0tPuq&1爳pv9L=QnBvjr!`g[%W<[}??&RL5 -q_Uazp~^>lFÅ1J>-s }k'PF.ZDxKثdnn}7lv⍹Fe:S(,Ptɡ{D{VM!x'(ՐJ鐠^rD,Yb_<Ĝ}KRjPG󮣃*e+UhݓjeQԀ@`7 [F=B(:U^43-lGdR+mۇ}Tc &9F zwk{>M'\eb(]OU D>MGS]|+7i+ ShOc*eWؾ)ɵi&TB0'fCǪ{&S@;S'J?xvHdȏ[ݸ ݖ8}ro"LC)aQPšYfIĂSGZVc5i!==H)9Ft̘}vEw)d˘DlRVF㡃M=M^` M0mL7Q[1" 7:FT|/]//@)z,Qf4,%s?#J_Pɡ>`_1hj J}®'I`Wg|5IMVǬNSꄐEXʛ&7+}BeuAdMQ)u  tJx;Zn8 vg=,:1YU {}r=,'\/)[]Gq3G{9Y &5 eUV7= B]d Đyh~ybEpU[*SVc$֐|4qXܕp$1Ḙ/(SΡ sʸ&etz"%V!Z#L[wa+;H!^osehe)jкEH>I9ֿ#$#s񬡙c_8YVw((i, ms%Q{vUe /qŻnta V)1Rd]Ud V_6oYYA5wx$skJX; Dh tTV*fǘ|CֆE\A񌴹%AHЦ+IQP|#/KO& '=/z Ӯ=$@5wے.u^NtyR&rn4t󖥽-*_\Z("`[.iv 4}Oe4ܑ)2@? j}SӶÐ0ᾟo:e,)T#P {UJG+qM'bﺣ5*_;z.PV-:X+";(/+/Tn ˀиyTC/ }0;b5[$-ᮥ-c36Vkn>"EHYYs=#5je8)Wy9iy<$S9G Țʢv F[2~̅A饞3'}3n2펜op?s>^,&ݨU UZV:t@9K35-?̴DNToY}tej_4RE8I4dB8YNMCqмȻ$:6*1'դ^r#˩Y@ar;e0w#$;ht}.H܁ˣ:N/Kr.'4in NB92mz|8Zt[¦Bخf ("Ͷ**Jv.֎~DK12z zEw31=c3y n.p ]1^p0qܺiN W)zCtX h1͌{ {C뎩:c/ȾcA#3)DPG FA.Ku: 7﷩nS+nGMJwS$~C_ӭEOgz485֚\S<>rw\d}[#0S[_bmPsz7 I9Vb:i#_+.htsrVU,?^|d#m6JG54G缨/ݥ{eΊš|O^{슪jn1'[yk+ލ#Qs1G 5a$^l3db[\0)擑$jrX|G*HF'5Svh ƭP0[Φ&a`=t+,Xף́^kDT%|h\0{`x 80{Y>1ivLSX;\qéY7Ć?$Tf}d}oh/nf5+pr?V[&"ṋCI&r_+Xܡ+ e5r?XrIע(!Uf/86F8cģ&<_;m~=)d*څΊaO-nu}?3VKK`;~~C3UB$t@Ӧtsr'W7bEN[j pՙjN\&4R](w'FK,Y)?Nn}LEi 1yf 0NSi欫NiumċiGä}v_`Rͼk=svդA9_;5ψ;dϧ _m| Fu/Nvw@j WB?C5o8AEDq\R#'ʪ,[ₕl n̼X^FF-*4lmB6K4aR&Icl P7e`p|~n` ?uJsҺyIR'/gWi5$ {*I~79e<4JS>5,9khyi' )Q5niVmڪ5fq- $5X:͙ PZB#J43Pq3j`#cjh7et0IPFwMj ;)lW}zoB`lEUL2DtXF`d)B,OC7|n" ,SⱠi*]j;'m/…k Nnjmxkx9x~S'>AޡM<} ~BrDjHmL<!'{ه]{[SJl7sk'ZxՐq&2*31S!xnc|IwlY9""#BH-U) sVx4IR`禍/0 QdQZ46?mk X"ؿ׺܋^EPUNQ[܎hթiҞgt3|ƩmyjP|+!E6J+1bыcF⸑*'6^V;԰ 0dxU[BGuiH$KE-q0jMcb+T)[&Ƌ~jJPz^na1[>4&[Ui3ǣgνMF^ cp-P~&;'+׬ks}c*@o[9|MpK6.\+2\)"  *g1[/[$b|JIúo'qX'svݚ̫ʜu^\|Jg0NvdE>=k\CU!_s^TI}K57Gت]AކJkʎ-as6>9^ԓ6#zM.cD%@uRiAو謪3ww8Uh6 xgXwyf5+onܑǘΥ :4 j!os#!A( 0DX; UN8 r$TZ26MHisq|-Rnd4GldYX(U?MV!"+A}9 t&#Oٜr|0#GZ*ATjiCqxUlJ<1K2)c ;Ž1 *K.ͫ P`1V37i!~ՇQBQ3ׇhi7?o^^at;0&A)rj^·/7Aێ*72-3_Of1]C'_y۸3J]yqa%O6Xr3^((((.ss䨧Urk!/Q:Ho*;aea;z 8VE i±Z^W.' v$Q[pcflt'I^ /xLrAՕO2>daru4󅅧"h:bg0NAA]ЅEkKwCwA`tꌙV_F/gG.M 6W׏Zynl%n;XFWZs>0WϬ 9xeQ- hx'Ed֍yR{ևv4ڲbF\yiRCgS0+m~: qt(&*C}Yh8FaNޯ3@x JȘlLjۤ}1sϙߒcVFNf˜MT57i~mnz\~^k~*雏PjezRV7ijꩰn&3 EoF7 LWqއl)/4,^{uύAQ倻gJd6u!'yN-h#' d(OwFkrOD ^F2?G n [TL{YUE$BQ 5F?q 6u^qīX-bTC``mڛ|tXp(/d THЄ g hf/( SN^tK4:Ԓg!V:E^u[^V*E=\҃>G߸U髀0qqxUŏdSͼ5M-DWb$ 0ըBlBj~'RVF9ط%<~%ʹ*'ad:CVG l"_E:\ąLGu/ZAeܷ3ؚWk΀5Ils,$so!-\ 7HgmɲCh}pGeCM?NǓbf{j=yIb V?Y> C򰬏\qi.*.B_^I^F%u;Ŏ!̕0΍([RNOyG^pǸ(DNXCdB`<_Czk7/#m~aHad^%qYrI=L~x0ĵhnY٩ =CoxJ=j -TQ?AxXzc&a2/VPb_2ܱe ێW?k/rQ4eqx?.栗ǫ$yi{Mjo~yQ:` hb!w߿}  .w[`?dq!n/ +䕸8-7STEE'ԈeqgLe6q}3"L&X17ϙcI?!]yB箅*Cںޜ E 7yn`2+6-jx1eb9,9iFNL -aNꏽ8VU K/+G3AbCi#)By<ߣSOɉǟ:iSȟ;BGQZ/BAl;e9"҄ Sc{ UCHQ@wR ^ y CsK86iϐKObs2\; ْS$C_≧CҢz@2-Rx4S{iY85(i0:})ОOŁA+R|8Rka;PIKڠkoTV-=$f=Y0hy5mAI?/ 鏟(g!81Y(!:6~3 :} 0zfZ 㽠]+Œn|?Sv;3"N4=e\\,VcF;"݅˖ YV钶2r-U=t|R~um߯9O8/nplcLE(VTVY0d E/f2CM!{'$r*xQ58Aw*{ "Mw6]@AZH*LH6# *8ֳf@\Di\ aQۆI:s$d 1^l9[' 2 P9I~?F?˃Op~$o5 |?E"T9;-դKD]r+@+?Æl)u47\K| <ǛU )q)1a9ףX୥CQZIZL^/FRK:VH9U&ߕ~r{yrߤ>Q`4E-W.{Z`HvMHa|HoNZ%!4*+*?D?M;`AY k1Wkްp0nsMV}eOOw7$#kW-=%5jK;E+&o|NFOS-!0T'8>8W\DF;gz$We!44қLf_T@acm v:%:^&^s~ UW0Gs 9]k:q=l֏dmR\JT0s -t:++x+EO5i \_qOU=jm_qax-U?_|":+tͰhu fM>5ɲveG5{@bBpnV̴jG$$ L8c`mKlNH:(EO\X^P~?D0ކJcELX :bRMMlG\IZ.;Hri xqO $ߚK{TJ{ʉl=8[IǨzҖ: _a<.ge֬cpQKDG+920DOIR>~#ܩ44%;m5"T<5ZΛ=r)w.gyh`>f[$v*Kۥ6\ιM4RkSXABl_EJipʎ_dǦU@,XN8 8%yWdpZ[TyʎKOd6fcDfԸG(Xzuyek7/!wI\ 2.fnU"&'{ܿ17a],"Z :;Ev>[fM%cE4?NCnVA7hT8駬'Ԅ5nٖ'J9]-?Rq;\؛;%҈P i~a/dMU ]D&wq|kV>U`&Yb ђWQӏ*dLRRYMYcDQ5T6Y'&ߏC7s9Oirj~і{]gʖSqgP`0ΝJ*k MYB^D.֪$>yF-imh-ֹhSzx40zT RICSN1r]/:ǛXs,K]Z͆5ՐY jC[(_&UǼ8è !z0IYlQ,y XYi^%~yZӾ\V[hTyЯgzjWK)ɩk=HʼnfE<,alw֮y'# ~x3ؒuBɊw@N=fRCcq5Pp/Fx:ǟ ]?%Ba~y&9(~#d>}ArzA^-bİ[ # InRmIn"R`w/%;6xތDc4>Pe!e]R nq .}d*ז5Pq0Z)1^wioxg^f=JR[Ն}*lTbM;E;リӢ*w넑THژŰ6 ,#೰T^xjHm>f/fոfÇ[27ǭJ\/gCw?)TPv 9DD\.W=BTɗP(s73-ۋLI1#ن2) :*[X=Goaǰ8D*<`oD7f'+.O9P,gkZ~ħL P?F'CcrXhz>P`63JԆe+)r FBe$el;vTA 5+۲OP k&zLұAͅ-ѫ` HUkAB7va %R}4Dkc1ΡCGMb`& v e; 0z2YR1Mp_dZ]c-x>₋0W!kel0,4HߝʖOeaYo!MW aI]^g.$3gpFe ^~vE}_!vo *(0nf~š"$_u*=ҫb>qD lW,,GGVX./'T6 +|3( rp!lKƏl%60 1r1lJexCOW͊^Qpa<{8#;7YVqq C1CI>L#;Hi~$ 9ԗP^s6ǟ+WqhGH9r&Vk*MZ5AG1RdNnUբc6^MFw Ͼn.`D-v>m#֒zD̂r~ y7ۥAllJ-b 4eiLFP:hox rC厎XGq4Ez 7{% 0܏7]M>0" EXD+*nL,H%5W<.Ni ;%t/)HF-!DԢ/m/^iaF<&3imZRBFE +!iNyjʱSSMAHʖE-^H, }FbuȸugdzHic`m% SE~sا< >MquDgWGr%M)Ϝ&0b[hXi{)|Nm#$~a7y5t‚me|0q5&YRSIWRFU:ai6ߕӾ}ջ\,WjVliQ㤓\Ro]a K#cҰ2wvgp$"_|I E}6PeJmW:ѸZD.A3'3 nO &n7Ugxl-xht>ЛRʃ3Ⱦ5< + Ӭ $SBli\ʇ %m._]KG)i7'$s0Pڂ WC$ZT$=^t;lN Wrx}deFJHA Z!NWiCm:J;DL+ͥ;HLЇngm-ڣPK+^gz&u9BhnI+`K^@V+~r׵p*. DY9 JGo3`"/RbI58aPO戀hƫӿ0)X 1&^P;P҉?/;DϳozH(|"B8YGㄸ&=p1u||1~\~~y镤qn#ÃcY8Aq21?~̝:HDykw~8}CL=ȩ%%eQ$Rn|!D|[f%'. L68@Pvn5𵕑+i)yMfx} U偞8S{n7%C%^_ϑ- U+"=Ydzh Fo}TVK8ũ ;b꠭2 ET 9wT(ARػDž4BteLFa~^Cbk<ʑ ;(g/CQvF8t Xls8ɉVufkvG7Nl"pf%4  O871Z&p#ܞ%42=)I!q " $e05!z76:֗솚6iO ͆2hA)C}Bci)}艰U/_VR͔.:ah2$eJhg0ݝ [ %өPYՠ׎+H{ղ~s2Wu} S(W>mKKrdvݢ2dD1t0,s&0zݳam݉x새aIpX.RxX<-w&61[90P&Ch*z%GDxdЮċ_M7*4Rg(ȗ(f]`*co 'v%2ndJߏ:d{E (c NFfc>˂T c|HvN^ ޽E)I!m!8loQvSeE! 0VzoAAAk">|zyy֝WxP|i%>+)ݽyCcmiAemD͞JN8hx7$iptѝatZ4q,S[h hg\9*B}Q0q+f m6K'?D?2_]u4pRz3^?|<|$AJl˙%Ԯ^L N.IK7traAY4)g, <Q)H观M" H?: !b~ 0͖Oz;g;ÿ~'*Ca 7&"f9u\!Hr/2ĵ!GMhOqWG綼k!du?EKLH1?T]-t)Ҝ B5jg-F#HmF2@<;Lw_~JW$f3W*E ؠhU4 ^"G%h;I_F"Iqy8ϡ8u*QVVK&_6٩wAAAGDXX)&g-j*fAIS ~^F_sVb7ҚlN68(fvq%;&]dh^. 靖޷u=lDxhKѻ nKw̳Q 8S&ԯ?vrn |X!PQJXs&3`e@֯r֢(Ov{#sP\V_s4"QS~RBN msX(ݥVjЯJ \." SAAA|JRO tiZT|[=iF5i_i 4cQ@|3B`8vIC߮N 5Tak+(((,nF( ]˫-;uYR%(]$N%jg\R=loz)((-( r6ovyZ=?z%V~a H2ߣbAe#I8]|\%NH VSP7| m1escXX"),?PaXkxQ.\yɿGvm;<KHEQZC*>9d>; p#u۰BH_UL¹rPm#jҤ̴¦J;@α>fJ_J V=hjERl_\ެwf\ .YS*RB6D#[\^[@,n .S)8,OѴq"κqF*GӔȺjq:Ouii'1y>̋e >otƈt858Ǒ {MxШvFѧ !Zyt8HMNa6|Ň&9B=[(Gʋ *$Ϧ\>=Þ FXulcvA:!WDh(r+sF;]1rS X>7{'X[цN4[-|Q ?]ƷO85qp9~B69@I1Zޘ45( wK2q ^9Gk298'3r+XeK|pvrthբ@)r/:g<016e z[*@CYH.BXWLUݡg}.TxK 6& AU ŽN1Ӕ@P3iLf\ %^R>lQ%f;ګ5(-V&?n hj+mJ/ WR~#կeںf~б: VgrrК.ZR6f! FE5VٚzY\n29%^9Z)̅~\{SZzİ>xg&ʞ1%3QAF\t =㢗k=183q9}8/r6΄^m[#~E Z[s}}m/~z=<-?Wd 9r# NtGJf: EwȸUMV>YbX5Y#xCGV+((X.pu:ȝ#\Tʼj/F8iҀ 7ymZܾx :6t[>`B H;RGn: [1y*O@mBDm?-] l\^ߘS?R4SX[[2h%' @&A$484tt b  e7CpkC 6?&ǕA9:k:W q5m4ViD+/ȿglAID)sԪXvt Ԕ:W_bgH)B+LJg;)&jJFW,k=KH~il 3b ۸uCD~#A {sI)b5f=)A]:Uh&B9'{~9=yQF[,lг>cly[ ڀ4@'˜'Tpe\pmo@E)WiJי: 5Ϸn!ǐ;' TouXn[o@~QG;,}E"r m4+Km*[* @.ArunxBeÈ-Gՙ0PA%{A/, QPd˴o4_8隍/CNԔXc ~.8wLsjAӺz7 l]FYF"先!Ƣ/Z`O+ikN?do LUcׯI'-t"3mO$S9fLrn+DT f;3sYBMYmw %B:öbZu}-O?]MxqщS ba"Eا9]~arhބO|7M'xW\"p§wzŎo7Lߺ΂c_F]m wokX>QNTQdcъ  gS sLn ޒQ8NǁXQS%]hf䖖9Vz[~Fg :O2եMZ̄֟F]u e~a،LbK:=K*}=:ș7{V+((xK0ƒ5Ԗ3gZO,V!N_; TR{I@QΡQ^ ?0D#oNц'uDCCNp$_Ӱi1jН;N2w'OgלěAZ!kwd!0No%[|4$HMFg>#i*ʨR;FFVN9"Ӓ󇢒*b ..;Z=b ?S22.|,jV!GQBUSB1hUqo8G9&{QFဒ,T1{ÎU{C<\L)^vXŠ)꿩ֳj3d>% bTJW{*^1 % `""x.n+#M`?_xE*:aOGM\L'gS3!B]^.ϟc:֓i7mgVPdz)AJٺ=AltKIn1 >.,&2+SRcWPPPPp? E}ݶf' 'DuLځ`֒|!Xc0 F7ƄhLʶvπ 7NTV1(jD)hRk]]ǕLzfуVX4Gޥ*BɎL Swys1\C&ي֧&?Dv>qIחҷeK-(((((H`ܮ೪S3XXfsQ6PvWWc8PEgNfqڋqQaj^Df*͂yPƬN4. YG1 S vet_8 +rsl(ҡ=[phuNѭoٹ%]ke?Sb&aռ/eǷ9 75BiȾDIUpsɯ$Èe&d̞yng$(NlwPIomT@uB‘%)D,4T=;dc0:y-j. 1iw4C6+#>psoѮ: DꕟVqA%5x49gBX3K#)8/7lB`'q=R?D$3!.s M;3x3{%>>b >F  )1"=Φ) D=2W5?89Ag_W@a` j].#HFhA]pF0hk(R"j$SĒ%7̬Qpy'9sF {/7+zBZtSւ:<8a6!_e'|*Q9ZmIC"6t8hL d_7*G6>TZ.`,F3HIT]JMWRE,+ ĞCr~i$~ϛ;P &U煸( gi 'ڇݬ2r UP3 8N~ft{vv}eظijcikbQuYTotT%b1mw^|SDD^AAAAZvx^Kh-"+(L{_KoL&|WM _&@HNB܎V Hb &aC+'CAN(sx1D@{[=M>,똏`71pqwq< ( OKaԊhXg( x{&gTH64bkd!Dԭ&+ \a( zچcuoܢK59ӓbMf;4)k+2%mG{J 3tܩ!T}0A.mz3cd5G?+z"S*5/Ur[2r nѯmҤw8 Dg6|G!^FM_ WC\\ ^軜=vI;q6Z@;wcGJ8W{3p# lPb(wqu2!ShU䷞,8Ek?lޯؓ)GtDB Fw'䩸SQX?֏ kz/Y]->`αᜩ]͖I%A~ lnXݱ)8^1~WiPbi%7UÌ5ߚ~'8ʜ50 nf8z\ xv MSs FN .TM3g1SHo4*P|YdNI+aբUFNAAALx-=7фO 5tGvbz@!w=U4M\ZE{ adnGNe xy{<gR5(B::rQKf'sʉwRP[C tbL,`$aN!WFo{@ژ6-)ՁE9B{_Py;i|a\|]r|oyKc6yt䴽Ġ82]­nNj  yiRpYSP߿gkoy񐜧82$:b{PqDB< qϘVs*A@ ժ˽('G4+{]yOXGq=ȩZ}ȓ)CSQ@L=o} \Y5.FD``26tX>Y)bCs9{59dҔp}}5D)՗;d C1z B~T $fo y׹xpSV;~ hg$@laiSv{USLďMg~1(n^ĊoDɤX`3h3# my8TPm9kX@T5oYs$c;w:a{8#3yȓxBW7d*" K˥|U''{ Gg>5%3TAAd_`X'! յdc~gAxGZ% Nz)(((〟@Hc^ʿ'O˩En\aؒWWCEhEKE62|U.' [;J=34}OUrd~ukw#I2CW({:!E{i']|+ G'c~ *)<-"8l=wS2]ŁJcܞW} :^rvíS2C6 ,t$Иb5Dј{a^NE(-1d"hy7SJqsnˈ9BZSH몬-XCtIfc-rlmy\U`FQܕZ8BM3e`ׄ#^qS՜ i֌DRmo`p2/@ ~v睐?f҉Ɉ*f*?6<$)`zyVFNAA-ë3<_1OM>;xEˈZι䏖.}m`zyٙ4KL[΀M([c\Ŗw_M3Y$(ùjUH2.C1UBEH(^{G>) T,2!1 ݂Ch/S,-ݪTl>hmØt g[,V FLAEYS ')i;i-.TG k}"h~=" npDD4ks*gf f\#sᦦ3vKfpΓ~~U< ;%cF [4O'GvCsAp;hx#"X*ODCŋKbNSpN!L\ Lq}#>8 k`h/ʞKb+dҪZXжW[5mהas.\Z b/s ԗՉ/.ĉ G,!(44'WCt/w$ooČՄ8^ 2L^ 4F ( KO a!`'zjV?pngNxGࠞJC#ό g ť`xj|wCAf~3^(Y4$j@"tFţ&ܸwSs- 1beFbxO [Xv3TR^dh (sMΞ De*VPP|ŤepA?)BDa}LLG }.g[7)^gX=^g-@9%..Mh{YqzoMϏa߻.km85W%mW8]9wBSwΞK #q&0AVxa>.7~s+> rgKe}q?R|UPPP0C\p%c"D`̜+K9hkp?P;KruB=iB?L믧l*hdQă4&>u7IBR0P2;Kn-י+H8.xKB['cO)Ҵi8Q 1rgwx5x|zz75j}Okf?N5x )diKbn;kP7K=Nnehm(Mb1Ͳ+F4Ӹ)FYb seaN:ip S/ѥx*z926e&/b/~[R7n_Mi`o#qfzg9 Iȟ}ތ?S*j{4lkUax B{X [b/kz{00e7FR~vTͭtndzO\"jKJ8 n3ke{B/TrZ#h@# Pnk < "ިOOSt O\!+g9)8:WcbˇHOW_new ]׀U@x@hx2ꅥXi7o\ 0]'PSt-/rU0̳v_.Vd<5K4x-;k-κ$I; u$5bS/_AB,nE ,L o&e%q f}=.)SB*]1Y^k=sE &q!%#Tw_uCAn;mCBGBZ#?Vk'UhŞy8S P(]S,ɂ̺v?l,Ӈ44BPCwRFġ?Bz7k`މ^s.d^ hqrFQ + A8GIoNyH]&WvDЛ2$ b@,'ߓGgWJhY&gEӨUJYŸD)j4W*] n{q)t۠%uصЏ.W[n6CTOYv'Ѥ>Y4BNRKCKnes1/Dnvڛ+djyywvbˆM")ꭨw؝tbiEW+k vx],E=mP+3| ήyeVwEڬ7Ǖ |-.e>{f)DJ k^s+N&iQi JsAa4.tLAecWA>"Y&u*p˖E*Ց"4w8kiq-@HKPoXs|D 7Blި(׏c65!Đc*Ftڲ2pi;<%æA!o-Bf(WQv&W=l'D?LkF۱Q(Ѵ+{}C[ÿdB$ *骙 jFA octu9.#b¾B>,>$0 Z9cqdu~XsAe|$ `XUg|ņ-4 RPG)q\PPPPPP9f5c5qUvl_|Υa;ߒI2FG~db`6ܷW/?hGEM݆?3W*t$V9Ai%$7t] h|m%iz]1*T LP*b?t71_ XS QTՉѵpf.bLj  , 3-ԩp |D: \R;/dC-XlԣOM+vGm)^'H)k*TmY` %}yż*#Swi\d+ܯhccL_hyi3 MJODaQe}{ EfAm<WnBu0 8W?N) } wGn΂ϡ` E.71[A]vXrB1-Q;vSdgⷻiM0,r`OMA:%wb㙑̵ƺHWOŒ?3X2r "9iW&*k :yGd w m~Qـrva9΅-)OTՇ{^mu",0mBmQFK*# OFTnc&%[+3Pg+Liq lB,! K+ESi8sx…ŜeC%ݔ<^"5O2e@L_x(o?3WUih^f+N˦D&y wn%EHr#D2(dL4]~BWdhD(u3_Hby[IѵrSUl:NZh/0}|OfѼ Ƒ0WpmU\=-,oSxqR9gi]WXIDl 0ʯ蓁#2mW= ~\U"KYPpuwwJ.)(((((X 3-SP}ۜԟ?JO^7$#D֚,!p.7ٜ߱14 OG:ae`Xb'BOfXRpp]@LEVY>FHP7B Dv$k}CUUljJh҅Fqк\8O hAUmC^Aꮥc>ʹ/{"$gVG ! ^$P";g?g,UvIrP{/%%s&Uo#^iPPvG*d<=utgth7zFށjgٔ@\Znu@R[ӳMOk鞣阍mӕ4U3ҜKI߄)(((Nm #M%H0G8F0x hryx|ȺǟA'm<,3|i%6wH8ϡɻH{T"pwkr+\PPPPPp :hJcG)N$|PN{ɩ<$]v=z>o&2)>(`}9&J`^ l <<ks{#BK,1YV/3K%(j&OfL{͋|* ;R2@F9mBXaD$E^yB|ܜK [F8!cq\nG-0'5Mn2(Ɩ3Ҥ{!"kٕymLi%,b/TFNAAAAAĝxq.Xp((((((X];X߄XT -=y|eU gH/bа_]}1Mfb>Ѽx.19s_C#ǭmS>  =_܀&cN&pOUɕ/ A4 i[Y,I5{a?QuKˊS/:TՇIGΡ{s1+\c3kfH$ܹW2gVda-8pM:tfoaxf!-OD #FZ:Ezo$O!NIfx@tk| 4sQx+1c<g}xfΰQ+O@UZFgj~$8s-Wu\u4[z ;xt2s=?m"kOBT kȵ0WD+(((((x_y( a6=ܹ5Llgʡ G?IlaSzl+~"Hr^X4ym=a)PK'Hbɾ.# &:=iXH nQqh_&=-]}ҸAk+>bPq-`ǯSj)SJ eNUB^4ȐzjA4$ܪg`_T@en}%i[El!0hj Q8bP5$qTuOE n ̺v7HD+O wc^8;}(uir;1nZwRzO ID +z="l|ݽgQ5AuF T(X>:ڟrho[L+u4~}wdP+GW윒`NT\rǘ\{t> 2 m~@$1I{m Bb1榕_t389)ӈ=IsFHC=×VDX;tkdJڝ{>b3]}F߅m~Di# ӡ$hbOMA [b/JF(T1i:B#Ѹ֟1;qW`5&yi:s|aEV\ؗqkp!2 ۭ*xKr@%͸EC7TBn2rDcTV~j\!hQL?O= z6 `+j(C/? ?DS,p@:vU< eyY|GA=6iKc6E!FOAOeSjUiyP?r/Q97(v[4};5;=9zYF{>Z &X"Vu[39BQuA`=9D:z6E=)HAq-d|-R s95?Zs +=8Kr+̋ߍT]5 b..}cls6y/AFL*?~y؎4/cid\)JnLͭ 8$2<_ܺD/¯*I<]S/'C[3sѝ(0!QVԭ0#`<ޝ~eVH/ H$6m5ڎڢr_U5nw /]3GZJ!sIX I_TmMz J)(((4ۂѩk\V ҇=B "BOṠ -/(((((x;uڀ9X?܁u.Xfgw$3pOՖNg\Tސ 5T=Lf60LՖU`M l^+ 4t:1#a../=) naIjhur1s SB0*3'EKGB\ZS2]8V|v^41H#mϪQ!t(NDKjqU.e#NbDH(|r:w2~v;(]xr`lsM-~ZvR5 Ζc#F0WoYw3ј@c٩h._߲~^ի:)8/s q͈cszB3RĪVuҹވX>^"A걧@hE'5-#@j #jR1f# EU=aNX@ZPOz_AK>.P`I[ogsp46e8~]hӜS2ZV'r~xV'>rӾr{%A&<7;ޤǚc^PB ut>M ;ӰGG`h`h6mwDZ.J(ƏQtyUK6B߂K(*W&H/?Kqj ^z f5 /T` 9hy %M ώ JP+w@W`ě.HD̂]O|vفTCտS|## Z=+@=t[2SrC8Idz3\q:2G2v $!jAKȬ4OΆ%=KEB('IK,=Z[vNgi|EqX1mdyh]MI8ky,Zv& Ieԟw1 gK%`#/WFNAAAA'ٕiNAx_\̈́+ |q ^{FɠN?UZLږ8x\8K-= >!P6 >!w1ה]['f Li2!Gj17 +_k" ?W~mi9 ֱ%h/;9-H6.-M>I cm|7Q5^K%8[?NI񍜽R#%%j#\!(n|34 TE`fUŠ#_V/'nY$Ǻ>"HI(e2'E=ܕWg/2.sۯBF IC{ŽKSyB+c%_'uoPA;{ۤ5CsgwZR鵞ٴ6u΋י/7)-@}( I^m8Zp&=g> (ZAAAAA7}r9:EV u\Z)((((((xC"A0bb1dH sK*~[^qIgmSbc&](bn&}Zt; w]$>/# ck:p{ޯbiע PݧL&dP790sP 2BmSIN gĉ-3=;Q8kAcMw(q HIxjZn4mMX3VdF5!6Ȃ vv҈|W$m(vU~w K2M]﷕SPPP`xzIoWjUV}-D`s垤4=|2}JIaϾ@>$bAAAAAAA !/ ۅ.cJH> V!Um0:DN?G0&%QͪD Ef\#Q\ I9d"32Ɩg Wez%80Fv^1 mVMw,ș7RiܤVj6ޗBZ0n(C˪_]Ǟ}?ڞw//JUMd`9^n+lt@\V=x#Ǒe hGvEEfk PXm{d`4H; R!A*v!9J[ f UcenF{*sw+7s//Q_RqU8] &vvY!XJ\?2:z3r͕(^ČF8眆sODny揅q:ȁm읋8( 'w级}J(UfllL()|zv9 '0#Fߙ6W+:h <;E;u@[oŸR_ϩ5/| èPX6,{ATT<>u gp&QWޥ^'Up]sJ{ju*}eY?bvy !~ Ҧ<{Ʊ x#JQP>|:0]S͟-Z:GMB35e _]:ޑбƣ=~bB2Eb:QBCv[$q,yd4'jh!N? "3؀rP?%jummTf(!9Hd,OV/UjH0Q TD,|vP~QSWw%3}iECѤY T̩ʎVJqwSwv mLs/xwNCqY͚*6XiCݝoYug z>>{Wlzw~oO.6d $[*H䋣a\DT5**sȣ+ⓛ*i37 g|ջ&gYa%W/%xx趖}Ŏo"<˴_qC N?a[S?he%w -2gmS_k}rY~uQVTGhe5M @-9&h3G|wyimOsD.-srFJ pJ{Ȅw0LU*XKjZEa4p~>ŞnwX:hFl)gwFZ.h1)5M9b1ĽؑZ T4ƥĶ|}BYyv td;SAwU g :k>5ۦ-ƓaU 5҉D{ j$6ZHo> :u[vfa&qqװ-oCIJ0${q۫|eso7kl5qؘXM,zh1ޮhܹ[.ţM^o{l@&M4uUj~mXJOpБZf:/~na.\%K7YNa"LuՔ-uqϫۈz0) @-7:2$>@Zg:XQ'wԃv*MµgG"e\7`n󯓼 KiדzѲ(0tbT})ۮ KOVb7X6Y}>:i}P 2~I Cu\0[BmGOZO:lGk5P"k}"=}P`{]0k&|F[t\o:L0\9트gmŢ-w Me7WL W ȥ Rl5dzu\5\1unZ[`̀bv0vdID?f;RB7Yb̦oS]RSrI,ڨ_ь8 I;(ӛoF$]腛H:j90Mg, S!r4|ws応8eI0rԶyLr9a;3 u5N* 6P)VUr_i~MӚd\aD_cw#(h;vhA7LcjʄMΐr5;v.W(I:H2ke!~'ŭyҋ쭻t->2:"{j:rH jYVWv!|Eŗv=iZȴWK5miT]JF] +Jʯ{0i83$ٮ$s gp`-u P.}\7YN{#Fdk[|ߌ$891͏ ڣ XšZ׽9hm)5ED|lGW13B܅E9;Ű`VI,5t(r_K )]vEzOce)c4#Z0,D?"Ss-:vT:6-xX_CZ)tMy{==ٻ4j9dP5؝gZ `2/2z <4"ѻ9do]Q## A|З3N/M}fhд^_u;RVj\pzM]o):﮻QdӋ(*ĭz'r`vWt0?vN^[;Ռ^3 qok4M%s-hLu[m#T{Bnu}y*4t $(sDoP[u*ߝ:*!IZ+wgi3aA!ؿ*ԅ{=0w652Zƶj>S]*qMOA5PkɁћlssZo.pfDޚJxZ+ 6wz'R+\ dKUKMIq4H>'2^G'Z Ǵȫ*ĺ-m!s~&[4"A3ƆY1 P9D%W'6{5YbGR5vPHIjغ/o1.#3ӂZ֮u +\Bv(겶&Po=Y>˄Nc_~Ei(0|yUu-S׹<auv.!v'cηa /{noꦓmF5Mj>RjC XVnZXG}VkVwu8[P0fUgFf%GAsg)+{A2Ev}oِbbZ0jJ["eխ}ˑΥqJ9 {%JIIp–lPZ?f-f17zƞ0IGf'=]?4/cX0w#b=Y_2re{`pUo#JF֊6f&G +ԯ~$wV* YL(ȸX #Nn\$*wBֺG<ŷlh~Y"o?/s_Ճm`wtd1Pn[GrO1mm|n[t⊏Y^$7bd^9:U0m_]/QI$c*{:EJv0.hIۜѵ>:^;:=ͦG 5Mn:M1:\D]w`0V˿Z";>+OߑI߲%]w{֠RuGLՊ%8 &-þMzZ$a**N^8~|wV*eq.OTryMj؛tYY<DqߜNsВ\{mpO9~X|'|~Wʴ̼s6w`Hj,UfjްZlϽ#4ECXݴee Qcbj %`.oAlR&)(L?~$QRs)jY6'Cĝ6nPc25 . D*'M?\<uP:q'z4ґw6wOվԗM t~EBYqZ }h} 3L)?8E*$S*|WXGkjj2܇ ԥ.Z>LBd֔WSB'} I~Bh5] ~b g[MWq=?(#ti$Wnp@giIo4ndҶ.}:^`JdWjkI{9d$XUx:d}K&g&59iCǏJX!ACQ:z>%'#xnZ;x6 &Qv) y?\Lc,/sy|aJ[=C(Z}N^'7V*AjZlPptw4Nm+\{l Se\5-+ 8JG||e@JYw)y䜏iI'o鳒;71a{zAOf:P5ݟ?g4[Odґ+Fs~qo>qVEfҷp8jRB6Q"{|_/7Ӑ^8M>JK|﹙oL\x7.#i{IԿx1^'EvYi38?=5'QaHof/~4]EWhMJ8SRk#j[,3õU =\{[vG#ϕ8-{ifXw} )&g]>X7rXkSSL5[A/&^+FQ[vzꮪB˳*G tOHŲǬZh%zٌ̟޸\˨o==;En2};T"_eKo͝obk\g7E<[b36C$Ha٫iKf`)/XhDr7pPg_U!'װHZӧ P>_iֻܔPbÑiq&n}39ۈj5su1ړwI!8gs-~zpx:tAx pܰ@kgsOBO߻]qޅ8[$` s:.r:? QuH)z-؋o^-S屶=f*NǢKu‡%"_f!u9OsH jlCʃ/MPa'7_/(j2JiP{*qa`t0 vibܓ}aP "LJA;AW}q2eBGb!^{:"5sM t /@vͪN' '٠y{le ؉z h6/Jb+?ٮ8KO/,*7u*s)W<5LR2Y3bH~\s pb)i4L3ۋhWuZjQ "-9'xѵ]ͻ %I۪CZA@o;ۼO(Vٟg9R&. |J]GzYH cܣ I; {zM%Syvm-x[

B'(M$ox=&-{gfƔ5ELkB5ꅘVI;f!g=Z/=x X;f+7^I U;K#"Ѝ\lrVGo"<@s5[!LYQ;&T+=H׿܊nGFecju`eVfkR(hE۩Z)Scҡ%=LNh^I]up@>+'e3wu83Tj;>v?d-'{:ds+ٻ *?0+L&8~vOW{'~SހrG==0in<9[B.T%it CFàϹ{7Y΋ 3V)w)_\ Zd +RK!viXᥟ!m OGV`է}z61ClIW Œk:dx{y"=3uv2^[5oTS6&t8tE,:ZcWLZ.ؙZ `v&<:BF3|U?[Zt&L 2[=FBx. Z78)KmӪ5̍J~KVx(I؆.UjI9 X&HSŽUL]lqOLEEGӆz11Ww2y%ϩóၦwe|GcI43ΜYo:ZW} aTDo&SD 3 9Kp$98wT;s#5SդPll}L^.Vu:_K_ 0wk2KR&ۺң%]I]&z9 r)yJ tnW_ǘQ2 LJKK> # |i]|'3/늢ẉcLmKe;4bUU\-E)G.3:+by_o=S+^;߭wϪ;Yb~{߾?Od2(ҲU,>dJDe^c(M~ɣ1h5OU31PZIaaNF;C{ _zs+]֧IӦU%҂HRˉS⨦z\}* ۭa;m DײaBJ˗$ڒR6CF+4 )oFCK_ʜ=eNȺ{ARfZM6rkj“}M ,鎹yy{z_A'* \pTۍ/OSqn@nIqtF,7\+wt6%S@grڅ kv#J[UNQ[iu&HPT,^Ǘ ^Zof$\K_m=73тWϚoq&J x^1I+Ycl[Yc#-vAj+Fsh5eg_R4OI09#%d{pn4YgUd`̗j}|/E%QT+H5uKqtb3#?,wxNr(lX>cnb.p-3w-]7/l]H3JU#^LQUlQ."XOPY{}ֽւEGA/,W0#]# k>2}2%7Hx8j hez6bA\״*ל~,bqx돎RNFo$$^sQM1*%F?n$YdJUVN*F 6k[&g_ ĶS5ܩ9ƻ@\;j,޾m%ͭQӢUʛvGxɭK\􌦹:_e]h[&<v;^'iy+Jlt fOˉW(#NUkILRXjCh5%0 gG<QPh,yf`@+n4MCoyVjsg,3gT{GsR\ do^̡uv"Iݎ(~;^23+#=BUJm#ewJQ?k.s ';`{ orm>:Y)HwL߷慏^*N椙y2~ZwTrtܡ!`jm~p-2Ie,NwN BHNջ"= ?b=Uj&;2ܧSTxhr;5ޠMwuj=.ZFw "ϭ$9%c0}ޫIW;cf⮥j[6:{VsUVg}j~5]k$ӆuJ&jkYRr0&.?aJ,y~A]ºRIj*-0*ȥƣ̀q5:Y-z (5>*||F]DFW+Lt'ˠȧ٢g'v͑Gb'_aFjQMCmp۶;G*ro%egSf'|kp]W2ջFjEEҘ$R}Ƥ8:yȊ 7Iӛ269nكYk~-bW\wh-}Z~?Ks/g,ܶ[0@CVJNN,+AnLYU٧q~tMx|RcEQ'?OCg#Šj}txPEd-V#Rj<9oqنfGCΡhz :]2 ^$v!Z%wh.jq!p|jԤi69|pu}* 9ݵZ !yLDr+>SBIgt\NDuJexЅ-,f?VƬ7tA rQ:BWSa-Ҥ<>rjLݶ\xoM (jtO [;D-88H>Ŏ9͌Ew,+0N݆ =6(k`m5ؖW!_I{퐝GI| P)qXꚅvG4ߢ ')"nJi nQduG О?͕%ϬŕeO*Jrit#bPs[_2&,'ά<@b4v(o;tg'?ßkBF[~DίÛ<3 T7;읆 sKIh-Itk_hiNO$50̑^,ORDۧ5JTdO26obw; AwZ{)2)7˺a vj]꧝j~iFm1)֋V˴ZjS1Ä x9q_֬szrjR p|`PS\EUGDR]~m~s?Mx-HKG;k_HɃ]TuAޏQ<_O7};B4|{vez#Ck ڨc2i=jbQ@xR"!͋s,N3H1m^JwJ"/\۾}v>4F ZVRUzE|,SF5Vs\9<\7aYǦ8lLfHUjoN-w3Db'_3斃M]UL_I6#3JՒm~bRn7r8)1 g^(QZrʆ=KRkgHGqwtFmLt o/sKz|=LxA|wZƉNy,^lŚ^ VቢN͏D:#ʭ \Sz}䓊hlTd5Ȃ2< "_^VW|Jsިi7yFR6ujj nI#^Q^iBL.YI\!́TZWGZ)j yQp#E=WiVIֲ&)~;Ub*{]eFX&GXjh??K1,U YJO"&bDCH֯ͤ2ZP&t9o딮0wF2@dر9yjԂ9%<:"N}nfAIsQ_$پ4ԮLV:-Z_ !+Iu\Z>U>+!H[L'չ3d3= ⵿'l干 Vǭ$ fg< ᣳ`ђIzޭC,[*2ƃ5͠dm٬m,ֽ/=Z^OeGg[R$-}0'&~S_uԾ=ŤUD,%QԎKĪ?sgXQ_ex] +wZ bs"sp;ڱPS`dVk/5_6D^'->SIea$0dy& 5shZ="}AjM_Odw.I zmC2"eA,զ{b-ex,/TK=óvh=Rx˒OV՘\]d_4<ݹ׿f< E&,;sjiwҹ?ϳG&=\#On O/^.X]CrytȮ}ݗϹZ{Gi>XhJEE+F--A.Ej>|n'#mM{8ޑthC}W;ɩ]V[ts$Iz7꒵׉v^!^-U&AΉn;qc{76v5Vok6&ޔH:3~6>(Bz(9GSD1:ο>DW΂]KuXe(I^ {C/ݵ\;_VNfj}5O,Zlt z=<[LtCo{s~]Im֒6JZcl8(x,6bK$C>Ccrˆe+IgW"d8 \WC?WGQ K4ybxZPV^#9㐑8P耫S;\1aDEVGgw̔}QnWc|f=eAz{oZU{RTDuʓh߳ZOͩS|A u S]uصW4DdzpR}(o̺uy&uAu-WQ}8쭡Ɗ4z *([LP\ǟi]Mɲ -Ŏ.#>ϛoH;NօV"Z(x,O4p梉v6MjJ%@)WAiMU.799pU;픺T?PcRʡNj;hT{W\W^ⵏ8w{rIvHL8HiɗDN|nHk]Jᴖ ]XW=k9ThxJK\pYcjuҌ4a_J ˿kU3D6 |9"zdš0"vP;>oOe ??* wvӬ魙|f VX(I$`o:$X9e'uB,<8LFӕu14[Z2#qcϢ [,pjѻ6uSujK\SPKZ `Q8XB)#+3ݐegaYJӇ$ǟpC2K<0SdfRu잣pE}DAވ˄T!_2p8X:=:٭uQ{}1pRGS7~DuuWy(W8Ԅ[ tZA CQܹrTֺuxrL t#N83,Z `Qȁ:nZ`:t}`"ʌ ]X;sRWjWuyeA+2 qv2皓oϿGzv>@;5LRi4js:$HjsR_a?3is,jӞ:'SSjj-CHeusK6xP/LΖvivRSXrj,a8g)0/`#!s)hRbv7,.nF=Jj?lW^YwD W_g%QpbQ2!nn5<ϫ to}Ǡp2{ w×6^]>Ĥ/2֡nթ A[ Zs#Zէdr`o^Gm,;%K~Ŭ <@N5JwWh0?eJ\V8:eѷ9Nk|?SyqNDml\JEjO`V,,ՖQGcVPW 0UDM5Zu7Xّ{ph3a]l^U h5DvìI̱kݦpOb-Hk?jzx[(a3LkZD3krZHi#1coΰkIiwIu:5;0Zy!+ Bv}j'Za\ZoZ5O"_x, 9Bh5?nnkW] `TnB geql.BT@gN5U)2;?h PfQ *$;__Heq&v,a`͏֨-rmX%iXaٙ;ЈԶRsʟMJSID'芃io#IjolٙɸvWN5vǺ--!vr^ҝves dUE;C5=\2&Sd*ꈒ0sCGS8n8iv1fZ ?@hőާG_4tE5R8Z nRW*kZvB, 9^;a06loNpuf2^ ].cJpF)q"V3Th?>B~VrkuũStG(ъ#$sC6㑽V[~=\~md0G,^Xn 4 `mxO1>ޘ& ο\?M ;Cx, 9Bh53¯m>1@,QDo|nNHf^^rrSM c`_ t\Z]m;U8C+?m£IJQ &yL؂: QJ? ^$\v^+_ժPTEA1􇺄J#'TD VTe OѼÞc7)u& N^Ʒ 7;%8KJ;󯈵͕0SH:-4-U+m {-8x\Sd3c@m]z5!S]fd ݶbUerMޘ׉ݤ (x\w{iCZMf&/f C<}N9[_Ecy&ᯢGџ'SYnEU~jFǕҖ+7נC9ZmMq7Je\ȼW-~bW^?giOh whQZ0ZNݪXrj7!7۹~c,'E6%G'rtH7??v;a'DX["l7P%lUYMGm%rJB[7FfR5"U*i-\=Y&BZV2lXL,}|s{HU~S\5-USHnGZ:Us)Qz̒5'?v@>۷s'_ur]W1n~H'[A e?SٓklL 6㣌w{sy'Vd=!4wX@!h l; Hk&)lkPp_e='9]Яi%h#ڌ8IB, 9pL!z}r'X{ 9= cu!>&RO-Bڏݑ8ż1.Bn?sLߠj`Y5Vpj޺*fnrYw ?u+kZ4WIU+E `Qs!g}Dۦ)`)Sv,j/W\ނ{ioLSCꎐ ~鍷&i)z]Pu/嶒?)b:[F/E2W%ݥq|.r $h/"3< J%$50řtI*vZ6ܗ߱3JkITrVq8֘Kp>JfK}>^)|WuQG#^prs9oZzNl`VXikmk]c'Zy딸/9pC3TwimGrc_EmrHs2CRˀ(S˃VXrjIX4_4:ZVSwcYSTu`t=mk]ypJGH;{Vbǡ"殮s ##wz;U> "֒W쓾J!ԴRSV\+\|-j[{.#B'Zs#`Qb>|_"Jum[Ϝ]ja~eG6_9$^r*mn>w&G O?>vk"9yGNϳhp.p)9:IWK-C履2= e{KGM > ^;g9OqiLj6g$ᰍlֶګ4\.y9յ~oXY5q7?ϕ`IF]#OI#-⌝4UEcgIVK̲Q[i3On~=\GCb=x$,VXrj4퍉tk2CbҋAQ2|sᅯwջvi/oY\N&lP՜t 0[y,5]ۈjAZ <'%)]mVȓES)c,ymJk +ìIZ֎c{J6i=߃ymf-C2Hk{E8 'X_Blw1[^0Mwk@j-%;Nfi@痦Ց ڠy-XqѢ驇7œjAZ r g%?ol aJ<3)*֫lzΜ2g_lä)$٫K6^I}ѫrؖE/4D(Jgȵ7:,+ uݛ0zԻ9qxb 5UeĹ{\5mh٦@R9݁m8o;)Oլ~{rS5`$ Ѱt{;;s0vl͢d1ԓ}*~xc2!Gu8 X˹}tNkǿ#mVhSik⚳}2$[.1Velj;}_::ДyEO˒L=;BK_Cўtz~@mk/&/buhAk[SCCc*o9r9~JdշN`%.h;K+%4 kC[/j{ZT]-{\9G\ľC̋*5d[ubdZ_>=G^^\}o%.7::H^gfq`t,İ\Q3uA;7]Q^]!]BYB=,gɅSQ/:#'x, 9p?n8kkncdSifLFaBS/(OUB*w;)srqUP4-;/LRB5b Ta|[Ln{ipiz]u-%k[!v6F/V[@%bfKו*7E7+m/̧ц~w#`Q8LS?E?Qfߘѐe ֌EWcu9-vFR-#VJ)^C~_d?+ߗvuL9^MҳCm|RYآZZwx\66F)_<NmLOtB, 90~eS1GW~9[kΙ&Q?_*e dQSv$B[$}m819~Ĩk>K72S첖.X0|N2T}N\p. G(?WSx, 9Bh5!pIfMz[hQk'QbX82k-=\,i-jugUCXtEߓf8l ;>z :WK(;7p&Hvm0xU 9pβStU\2_ĤN܂˟>gDߟ.8qю&=>8;)l6Oe}*%qeHsmKT/w?oSSJYz_1Ϩ.:IErLCh5E#q3Hk:=U<Ңq[ ,ڱ14v_(E[G,4Mg+Bu ܥgue>y#GmliiEj#`Q8XB8 õH3nmskЅ5ch.HJFRki?&ʞim;2VuH,V8o;s@ck]7W.Y]CMUktMLR):_9s۔wlOR';(65GrjPo5͝Eӈ`{UBvr#׌0>Ua| u4c=㗦4gT+6F Sl[t2'VX4u_ [m59V]RǡmK>v.7/e{Dp_оz/Ⴃ: vG-RXkT'@{$)$4d6˾k]m]y tqI.9pGF@R6rRZ x޽\OۧzrXG>L~WWkFmCb7PQzXšNmx!9GJ?Ħb5FouY?aX1}8ڄ2}1ഓVlO׾(5p}uJNcl>f_sW5ܿ>&Vrb_%Yʯ$_^Fhbȁj~8fil"P/s+z4u;1;‘jUgܼJi5d&]IC:ʰ\, ~detWlMys)%׾pɕ>oU,4A5dx.= 361W5RpZmޢjHF@R2r7_ސSvx[sv2W^ͣϽII9[cxР51 ^Owu~N͏/9d[Lif~1LaͤGQƔ*r3~|9I8c?(?y|L~Vq<[1M~?8ؙ$i&?ԕj;'}s^LŒu*:>}{e#|Ţ^^1f1ҌLl>Fҿj~sjz^fݝЉ#ez؊v:nJT?ǵldOT9ߕ#vWrSv͌xH]Ų"r-3HxVHJF۩O)槫挫VڲIJjը6,8xꫭN\7wNJH%;- Isk- GWNe$e# )Fگ!? 45T9Z# i"ڪV?4㎞Uomw-h6WޮRj>4uH){)Z?2>WM<`qw\0'\+Fz6r_֜J#_C#q>G`aSqvJw{1UqռJ~rG]1OZc$;5VHJF\%TUM_)hh+eR5ݐr:[S+S6~0r]L)'|ځAqQX9qVk97}u)3bV]6a+*>Ks^CXn]QJu~_}iG5jkPl+r"޼vGg-: 8a=-G;[h?{8[Jҙ]hˁ^~HQD%wn"w!֮@'<+*}ᯟ19 :ͭTU;CZtC};kl m_3m?[v>.5.!rb:}]['%h~Z2rj)mU*^cWŵ6SiH\ G _8.zVuOuEF?VZ+˾!ο%^WA6@Oq߸Zj1%H1}bh#m\֜?nκȾNi>bИ}?vkǞsDmۉPT}J+qY9{_&:+c6CXT#\8d߾RZ )9s۵O$ʌ%:^n3tM^{uȘ)M>n'UKg;N{2eL؃M+raٴ2E sb9IԜ_i% #]Եoc*qhaUNK8f":YErwUȓ]g`oX7SpRLPK$]ےIs(GSZo e^Z<o9h,{aϜy gR`[t'&R &zALˬe$%#~< {CE|NDR&B%)93,)ޞ.$?9>~;O:&W%& сHM{s6r忿 }c|L={-Gnn= G,9ӽ=WlrQYcwjOqgJ_O\F.4IfeꅴfBlqŕVHF@RJk>x[́ƗV9չbxk&v:>9KSж,wl֕]?z`q.0.mpd(3CtZjڒ2oOG71AZ9TC2 dbcW#%7V:zD勮H*byWr<)D UOVZ{u(uxP ][v\.jnKúPEU^W:{kFxK+w 9wqcdJ$e# )j Ɨ)7y}ΧF;Jk,/WqGމ36U"&S3z2qUSFWfV2r@?%DocvN@t-鹣`[pAŁf Z}vdƱtlAvv][lnFVU*?m2oteN`L.qNlcXΞl5WKk^n\}جstn +"|8Aj4z[g__ej0Łc g:ۄgt()=j)eGk"?wO9rF@"U׎'蔕C.e}仕_33 /3r aY۶JcxE;1'& \F@R6rRZ ܾ-zSiU_E)3dUZ;8yӍW ",e ݭkWNH9AfgeWƋCu4l0ěGޙ}q{rpVor)=0#Cs,ځ+.k^)8 _݆Z3=z$.9:ssʶO)tgs'eބtxf\3#"xe$%#[MU,G'U uj-p>qvrqړwNǎ?B$MB|*Ɯ&ZF@R2rIG~CJ7.|;Q9ߧgr/+曦<=%ŤNNw7'K~dI2rlߺPRLDy55A•8X_G6yS&9ʩDw.ˎ e\[wX+l?f枕ϙrjVHF@RJ`_g|Ji.S U잾tqUYtgVڋxjY߱s,# )9ycOhI,UŐY}Ʒt9]qn-z%y$dZ- Zq J _Flm_uoC:TW7bFb:>[3\xv8%dkj}hm>SZ )9I)rH|JeI΂Q*mf0(_&n]^Z&a>GdHJFo?>@gGtN+[?=']nV1$ # )9GD:>IZ-3SʕDe0j\)C=d/7('Ok?2rj0ҏ2 ~ )\ߏokzko6OM*~<͕n=gMqW6r`:țc{{k|a[M /;[='sӇjIu>=v1{cP9:cK%>}`EQ̞}ԕzvlGT"󦅌l$_[)Q ԛ>cl3=*=Un]=)tw7=7q-NCnk Χץ^;#ZZ!L OĔCjJ$%#9A>{O&G9тq>y,lJS&Ș{}7VEnQH6rಎT{{tٽS.וKm+/NFe_޿@lkCvn&RZ )9I)7N|^v9˲`V &xOF2>gQER[JF@R2r~jY2>j?dxV*bS}+(.׎k'tҢX6r a6آ8cE8>L(V6#+u>{j`=EQ'"\q05T.? 烏%Ļ(7#v󘈵{U'1,Ԩrz\_O0ןR09Jm[g3fgo i74)#j 5dvJxg#=˃ń64qU է42ri ;4}5$뎭 Ja19v𝗚{ya.Ma=jIHJi5ಶ4ΜД_j(ΆrXbT9Mmkk}|j@;C'EK;QZ )9}Ժ-C5x-i5ZWh9\<l$?~i~_vqeϔ_~]]{d#} =g+i6Yot,_XWWp**vw<0A,9Ic񶔝L|XwFiK |'# )9|zN@}yz~}>%a^c+HJF@2OIܩ|4:W̞K^NƷ 8n+9IgkoG:B_EdfL˶d$%#mI2r9IHF@R6rl$e# )9IHF@R6rl$e# )9IHF@R6rl$e# )9IHF@R6rl$e# )9IHF@R6rl$e# )9IHF@R6r^@B2rl$e# )9IHF@R6rl$e# )9IHF@R6rl$e# )9IH$(獝`0IENDB`_application/octet-streamOobplist00fgX$versionX$objectsY$archiverT$top"()0!12JKLMNOPQRSTUVWXYZ[\`aU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1#$%&[NS.relativeWNS.base_Dhttps://www.imperialcollegeunion.org/static/site/graphics/bg-new.png*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#ADk3456@WNS.keysZNS.objects789:;<=>? ABCDEFGHIVServer_Transfer-Encoding]Cache-ControlZConnectionWExpires]Last-ModifiedTDate\Content-TypeZKeep-AliveVApacheXIdentity_public, max-age=300ZKeep-Alive_Tue, 11 Oct 2011 17:23:04 GMT_Thu, 06 Oct 2011 16:15:33 GMT_Tue, 11 Oct 2011 17:18:04 GMT_application/octet-stream_timeout=15, max=99*+]^_NSMutableDictionary]_/\NSDictionaryB*+bc_NSHTTPURLResponsede/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiverhi_WebResourceResponse#-27X^y|&+6?EHNW`biq|~$-CNn (,@N`cyj{_Dhttps://www.imperialcollegeunion.org/static/site/graphics/bg-new.png O/* Breadcrumb */ .breadcrumb {position:absolute; margin-top:-25px; margin-left:12px; font-size:95%;} .breadcrumb LI {float:left; margin-right:4px; background:url('/static/site/graphics/icons.png') 0 -788px no-repeat; padding-left:10px;} .breadcrumb LI.first {background:none; padding:0;} .breadcrumb LI A {color:#0056a1; text-decoration:none;} .breadcrumb LI A:hover {color:#d1554f;} /* Header */ #hd {position:relative;} #hd .logo {display:block; width:145px; height:67px; text-indent:-9999px; overflow:hidden; float:left; margin:0 0 0 28px;} #hd .logo STRONG {display:block; width:100%; height:100%; zoom:1; background:url('/static/site/graphics/logo.png') no-repeat; _background:none; _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/static/site/graphics/logo.png', sizingMethod='image');} #hd .logo STRONG A {display:block; width:100%; height:100%; position:relative; z-index:1;} #hd .top-section {text-align:right; background:url('/static/site/graphics/top-section.png') top right repeat-y; _background:none; color:#fff; padding:12px 10px; font-size:90%;} #hd .top-section UL, #hd .top-section DIV, #hd .top-section P, #hd .top-section FORM, #hd .top-section FORM FIELDSET {display:inline;} #hd .top-section FORM FIELDSET {margin:0; padding:0;} #hd .top-section DIV {margin-left:20px;} #hd .top-section LI {display:inline; padding:0 8px;} #hd .top-section .user-preferences LI {padding:0;} #hd .top-section .mode-preferences, #hd .top-section .mode-preferences LI {background:url('/static/site/graphics/top-divider.png') center left no-repeat;} #hd .top-section .mode-preferences LI {background-position:center right;} #hd .top-section P {padding-right:50px;} #hd .top-section FORM P {padding-right:0;} #hd .top-section A {color:#fff; text-decoration:none;} #hd .top-section A:hover {text-decoration:underline;} #hd .basket {font-weight:bold;} #hd .basket-link:hover {text-decoration:none!important;} #hd .basket .basket-items {background:url('/static/site/graphics/basket.png') no-repeat; margin-left:2px; padding-left:24px; padding-right:5px; font-weight:normal;} #hd .basket .total {color:#36d3ef; background:url('/static/site/graphics/top-divider.png') center left no-repeat; padding-left:5px;} #hd .login, #hd .logout {background:#d1554f url('/static/site/graphics/button-red.png') bottom left repeat-x; margin-left:10px;} #hd LABEL {font-weight:bold; padding-right:10px;} #hd .text {border:1px solid #cbd6dc; background:#FFF!important; padding:2px;} #hd .advert {float:right;} /* Navigation */ .navigation {background:#0055a1 url('/static/site/graphics/nav.png') repeat-y; margin-bottom:34px; font-size:110%; *font-size:100%;} .navigation LI {display:block; float:left; text-align:center;} .navigation LI A {color:#fff; display:block; width:122px; padding:7px 10px; text-decoration:none; background:url('/static/site/graphics/nav-divider.png') center right no-repeat;} .navigation LI.long A {width:168px;} .navigation LI.last A {background:none;} .navigation LI A:hover, .navigation LI STRONG A, .navigation LI.last STRONG A {background:#fff; color:#0055a1; border-top:1px solid #cbd6dc; padding:6px 12px 7px 10px; margin-left:-2px; position:relative; z-index:2;} /* Sub Navigation */ .sub-nav {border-bottom:1px solid #cbd6dc; font-size:95%; margin-bottom:14px;} .sub-nav .sub-nav {font-size:100%; margin-bottom:0; border-bottom:0;} .sub-nav LI A {display:block; padding:5px 6px; background:#e7ecef; color:#333; border:1px solid #cbd6dc; border-width:1px 1px 0; text-decoration:none; zoom:1;} .sub-nav LI A STRONG {font-weight:normal;} .sub-nav LI A:hover, .sub-nav LI.selected A, .sub-nav LI.selected LI A:hover, .sub-nav LI LI.selected LI A:hover {background:none; border-right:none!important; color:#4484bc!important;} .sub-nav LI LI A, .sub-nav LI.selected LI A {padding-left:15px; background:#f1f4f6; border-right:1px solid #cbd6dc!important; color:#333!important;} .sub-nav LI LI LI A, .sub-nav LI LI.selected LI A {padding-left:25px; background:#fcfcfd; border-right:1px solid #cbd6dc!important; color:#333!important;} .sub-nav LI LI LI LI A, .sub-nav LI LI LI.selected LI A {padding-left:35px;} /* Banner */ .banner-container {position:relative; margin-bottom:14px;} .banner-container UL.banner-links {margin-bottom:0!important; position:absolute; z-index:10; right:6px; top:6px; padding:0;} .banner-container UL.banner-links LI {cursor:pointer; font-weight:bold; display:block; float:left; font-size:90%; padding:2px 6px; margin:0!important; color:#0090d3;} .banner-container UL.banner-links LI A {color:#0090d3;} .banner-container UL.banner-links LI.current {background:#0090d3; color:#fff;} .banner-container UL.banner-links LI.current A {color:#fff;} .home-banner {position:relative; width:625px; height:206px; overflow:hidden;} .home-banner .banner {position:absolute; opacity:0; *filter:alpha(opacity=0);} /* Page Banner */ .page-banner, .home-banner, .news-banner {position:relative; zoom:1;} .banner-text {position:absolute; width:100%; bottom:0; background:url('/static/site/graphics/banner-text.png'); _background:none; _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/static/site/graphics/banner-text.png', sizingMethod='scale'); text-align:right; color:#fff; font-size:110%;} .banner-text DIV {padding:10px 15px; font-size:120%; } .banner-text H3, .banner-text A {color:#fff!important;} .page-banner {position:relative; width:433px; height:206px; overflow:hidden;} .news-banner {position:relative; width:560px; height:206px; overflow:hidden;} /* Panel */ .panel-outline {border:1px solid #cbd6dc; margin-bottom:14px; overflow:hidden!important;} .panel-gradient {border:1px solid #cbd6dc; background:#f6f8fa url('/static/site/graphics/panel-gradient.png') repeat-x; padding:12px 15px; margin-bottom:14px;} .panel-grey {background:#666; padding:12px 15px; margin-bottom:14px;} .inner-container {padding:12px 15px; display:block;} .inner-container-media {padding:12px 8px;} .panel-outline H2 {background:#e7ecef; color:#0056a1; padding:8px 12px; border-bottom:1px solid #cbd6dc; font-size:120%; font-weight:normal;} /* Promo */ .promo {font-size:95%; font-weight:bold;} .promo IMG {margin:0 auto 14px;} .promo STRONG {display:block; font-weight:bold; color:#666;} .promo A {text-decoration:none;} .panel-grey .promo IMG {margin:0 10px 10px 0; float:left;} .panel-grey .promo,.panel-grey .promo A {color:#fff;} .panel-grey .promo .promo-text {display:block; text-align:right; font-size:120%;} .shop-promos .promo STRONG {height:2.3em; line-height:138%; overflow:hidden; background:#e7ecef; color:#0056a1; padding:8px 12px; border-bottom:1px solid #cbd6dc; font-size:120%; font-weight:normal;} .shop-promos .promo A {display:block; padding-bottom:10px;} /* Accordion Section */ .accordion-section H3 {font-weight:bold; background:url('/static/site/graphics/accordion-arrows.png') 0 -36px no-repeat; padding-left:20px;} .expanded H3, .accordion-section H3:hover {background-position:0 -76px; color:#d1554f;} .extra-information {margin-top:20px; border:1px solid #a8a8a8; background:#d9d9d9; color:#3c3c3c; padding:10px;} /**/ #mainImage {margin-bottom:14px;} .product #main-image, .product #main-image IMG {width:275px!important; overflow:hidden;} #thumbs SPAN {float:left; display:block; margin:0 0 10px 7px;} #thumbs SPAN.first {margin:0 0 10px 0;} #thumbs IMG {float:left; border:1px solid #cbd6dc; cursor:pointer;} #thumbs IMG:hover {opacity:0.8; _filter:alpha(opacity=80);} /* Home news */ .home-news H3 {margin-bottom:2px;} .home-news DIV IMG, .home-news DIV SMALL {display:block; padding-bottom:14px!important;} .home-news DIV DIV {padding:0 5px;} .home-news .col-e H3 {font-size:125%;} /* News Photos */ .news-photos {width:124px; float:left; margin-right:12px;} .news-photos .img {padding:12px; background:#e7ecef;} .news-photos .selected {background:#fff!important; margin-right:-1px;} .news-image {position:relative; width:248px; padding-bottom:40px; float:left;} .news-image .paginator-controls .previous, .news-image .paginator-controls .next {top:196px!important;} .news-image .paginator-controls .previous {left:0;} .news-image .paginator-controls .next {right:0;} .news-image IMG {float:left; cursor:pointer;} .news-snippet {width:210px; padding-right:20px; float:right;} /* Quicklinks */ .quicklinks {padding-left:10px;} .quicklinks H2 {font-weight:normal; font-size:120%;} .quicklinks UL {font-size:90%;} .content .quicklinks UL.reset-list LI {list-type:none; background:url('/static/site/graphics/icons.png') 0 -696px no-repeat; padding-left:10px!important; padding-bottom:10px!important;} .quicklinks LI A {text-decoration:none; color:#333;} .divider {border-bottom:1px solid #cbd6dc; padding-bottom:20px; margin-bottom:20px;} /* Footer */ #ft {clear:both; margin-top:12px; height:139px; background:transparent url('/static/site/graphics/footer-logos.png') no-repeat;} #ft .logos A {display:block; margin-top:19px; height:81px; width:156px; margin-left:20px; float:left; text-indent:-9999px; overflow:hidden;} #ft .logos A.imperial-link {float:right; margin-right:40px;} #ft UL {padding-top:30px; text-align:center; position:relative; zoom:1;} #ft LI {display:inline; padding:0 5px; font-size:95%;} #ft LI A {text-decoration:none; color:#458CB7!important;} #ft LI A:hover {text-decoration:underline;} #ft LI.copyright {position:absolute; left:0!important;} #ft LI.othermedia {position:absolute; top:20px; *top:30px; right:0; display:inline-block; width:100px; height:30px; overflow:hidden; padding:0!important;} #ft LI.othermedia A {color:#FFFFFF!important; font-size:1px; text-decoration:none; display:inline-block; width:100px; height:30px; background:url('/static/site/graphics/othermedia.gif') no-repeat;} #ft LI.othermedia A:hover {background-position:0px -50px;} /* Item Gallery */ .item-gallery {position:relative;} .item-gallery .item .inner {margin:10px 50px;} .item-gallery .item IMG {padding:0!important;} .item-gallery .item H3, .item-gallery .item H3 A {color:#666;} .item-gallery .item H3 {font-size:95%; padding-top:0;} .item-gallery .item P {font-weight:bold; color:#004d98; margin-top:5px;} /* Product */ .product .price {font-size:160%; font-weight:bold; color:#004d98;} .product .submit {float:right; margin-top:10px; margin-right:20px;} .related-products {margin-top:14px;} .related-products H2 {font-size:110%; background:none; color:#0056a1; font-weight:normal; padding:8px 12px 0; border-bottom:0 solid #cbd6dc;} .related-products .promo {float:left; width:100px; margin:0 10px 10px 0;} .related-products .promo IMG {margin:0 0 4px; border:1px solid #cbd6dc;} /* Toggles and Tabs */ .content UL.toggles, .content UL.toggles LI {list-style:none; padding:0!important;} .content UL.toggles {background:#f6f8f9 url('/static/site/graphics/tabs.png') repeat-x; zoom:1; width:100%; border-bottom:1px solid #cbd6dc; _border:none;} .tab-container {margin-bottom:14px; _width:558px;} .tab-container UL {background:#f6f8fa url('/static/site/graphics/panel-gradient.png') repeat-x; zoom:1; width:100%; border-bottom:1px solid #cbd6dc; _border:none;} .tab-container UL:after, .content UL.toggles:after {content:"."; display:block; height:0; width:0; overflow:hidden; clear:both; visibility:hidden;} .tab-container UL, .tab-container UL LI, .content UL.toggles, .content UL.toggles LI {list-style:none; padding:0!important;} .tab-container UL LI, .content UL.toggles LI {display:block; float:left; color:#0056a1; padding:8px 10px!important; font-weight:normal; font-size:104%; margin:-1px; _margin:0; cursor:pointer; background:url('/static/site/graphics/tabs-divider.png') center right no-repeat;} .content UL.toggles LI, .content UL.toggles LI A {color:#b4b4b4; text-decoration:none;} .content UL.toggles LI A:hover {color:#666;} .tab-container UL LI.selected, .content UL.toggles LI.selected {color:#0056a1; background:#fff; border:1px solid #cbd6dc; _border:0; border-bottom-color:#fff; background:none;} .content UL.link-toggles LI {display:block; float:left; padding:5px 0 8px!important;} .content UL.link-toggles LI A {padding:8px 10px!important;} @media screen and (-webkit-min-device-pixel-ratio:0){.content UL.link-toggles LI A {padding:7px 10px!important;}} .content UL.link-toggles LI A.selected {color:#0056a1; background:#fff; border:1px solid #cbd6dc; _border:0; border-bottom-color:#fff;} .shop-paginator .paginator-item .shop-paginator-image {display:block; height:70px; overflow:hidden;} .horizontal-paginator-container {position:relative; overflow:hidden; padding:14px 0; _width:558px;} .horizontal-paginator-container DIV {margin:0 30px;} .horizontal-paginator-container .paginator-item {width:100px; float:left; padding:0 14px 10px 0;} .horizontal-paginator-container .paginator-item, .horizontal-paginator-container .next, .horizontal-paginator-container .previous {margin:0!important; border:none;} .horizontal-paginator-container .paginator-item .name {display:block; margin-top:4px; font-weight:bold; font-size:90%;} /* Paginator Controls */ .paginator-controls .previous, .paginator-controls .next {zoom:1; text-indent:-9999px; cursor:pointer; position:absolute; top:35px; z-index:2; width:19px; height:19px; background:url('/static/site/graphics/icons.png') 0 -500px no-repeat;} .paginator-controls .previous {left:8px;} .paginator-controls .next {right:8px; background-position:0 -600px;} .paginator-controls .disabled {cursor:default; opacity:0.5; *filter:alpha(opacity=50);} .paginator-controls .pages {display:none; text-align:center; width:100%;} .paginator-controls .pages SPAN {position:relative; top:4px; z-index:1000; cursor:pointer; display:inline-block; border:1px solid #cbd6dc; margin:0 4px; height:4px; width:18px; font-size:1px; color:#fff;} .paginator-controls .pages SPAN.hovered {background:#cbd6dc; color:#cbd6dc;} .paginator-controls .pages SPAN.selected {background:#009ad9; border-color:#009ad9; color:#009ad9;} .flickr-viewer {text-align:center;} #flickrView {position:relative; padding-top:45px; background:url('/static/site/graphics/flickr.png') no-repeat!important;} #flickrView .previous, #flickrView .next {top:294px; bottom:auto;} #flickrView .previous {left:0;} #flickrView .next {right:0;} #flickrView A, #flickrView IMG {display:inline-block;} .youtube-link {display:block; margin:8px auto 0; text-align:center;} #flickrView IMG {margin:0 auto;} #flickrView .photo {text-align:center; width:100%; height:280px;} /* Main Home Tabs */ .main-home-tab {padding-top:20px;} #myUnionTabs {margin-top:-7px; *margin-top:-9px;} .main-home-tab UL.toggles {position:absolute; border:none!important; background:#e7ecef; position:relative; z-index:10; *top:-2px; margin-left:-15px; width:125px; float:left;} .main-home-tab UL.toggles LI.selected {border:none!important; background:#fff!important;} .main-home-tab UL.toggles LI {display:block; float:none; margin:0;} .main-home-tab .toggles LI {position:relative;} .main-home-tab .toggles LI .toggle-text {position:absolute; bottom:8px; _position:relative; _bottom:auto; _margin-top:-18px; display:inline-block; height:14px; font-size:90%; width:90px; padding:2px 5px; background:url('/static/site/graphics/toggle-text.png'); _background:none; _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/static/site/graphics/toggle-text.png', sizingMethod='scale'); color:#fff;} /* Homepage clubs & Societies */ .clubs {margin:0 -15px;} .clubs-section, .events-section, .news-section {position:relative; margin-bottom:40px; min-height:260px; _height:260px;} .clubs-section UL {height:180px;} .main-home-tab .clubs-section, .main-home-tab .events-section {margin-bottom:-14px;} .picture-story-list, .event-story-list {float:left; width:450px;} .picture-story {height:200px;} .picture-story H3, .picture-story STRONG A {font-weight:bold!important;} .clubs-section .item-details IMG, .clubs-section .item-details .image, .clubs-section .item-details .image-left, .clubs-section .item-details .image-right {display:none;} .events-section .item-details IMG, .events-section .item-details .image, .events-section .item-details .image-left, .events-section .item-details .image-right {display:none;} .clubs-section .product-image IMG, .events-section .product-image IMG {float:left; margin-right:10px;} .events-section .item-details .info {margin-top:-8px; margin-bottom:0;} .item-details .arrow {float:left;} .events-section .item-image, .clubs-section .item-image, .news-section .item-image {height:205px!important; overflow:hidden;} .events-section .non-paginated {float:left; width:450px;} .paginator .picture-story, .events-section .non-paginated {padding-left:14px;} .clubs .paginator-controls .previous, .events .paginator-controls .previous {left:135px; *left:10px;} .clubs .paginator-controls .pages, .events .paginator-controls .pages {display:block; text-align:center; position:absolute; top:212px; *top:222px; _top:232px; right:30px; width:440px;} .clubs .paginator-controls .previous, .clubs .paginator-controls .next, .events .paginator-controls .previous, .events .paginator-controls .next {top:220px; _top:230px;} .clubs-and-societies .picture-story {height:480px;} .clubs-and-societies .picture-story-list, .clubs-and-societies .event-story-list, .clubs-and-societies .news-story-list {width:250px;} .clubs-and-societies .item .item-details, .clubs-and-societies .item .item-image {float:none;} .clubs-and-societies .item-image {margin-bottom:15px;} .clubs-and-societies .clubs .paginator-controls .pages, .clubs-and-societies .events .paginator-controls .pages {width:230px; top:222px; *top:232px;} .clubs-and-societies .clubs .paginator-controls .previous, .clubs-and-societies .clubs .paginator-controls .next, .clubs-and-societies .events .paginator-controls .previous, .clubs-and-societies .events .paginator-controls .next {top:230px;} .clubs-and-societies .clubs .paginator-controls .previous, .clubs-and-societies .events .paginator-controls .previous {left:125px; *left:10px;} .product-image IMG {display:block; margin-bottom:5px;} /* Quick Calendar */ .quick-calendar {font-size:95%;} .quick-calendar .main-event {width:115px; float:left;} .quick-calendar .calendars-container {position:relative; width:155px; float:right;} .calendar {border:none!important;} .calendars-container .paginator-controls .previous {left:0; top:0;} .calendars-container .paginator-controls .next {right:0; top:0;} .content .quick-calendar .month TABLE {margin:0;} .content .quick-calendar .month CAPTION {margin-bottom:0; padding-left:30px; font-size:95%;} .content .quick-calendar .month TH {font-weight:bold; padding:2px; border:none; text-align:center; background:none;} .content .quick-calendar .month TD {padding:3px; border:none; text-align:center; font-size:90%;} .quick-calendar .month A {text-decoration:none; display:block; background:#d1d1d1; color:#666; font-weight:bold; padding:2px;} .quick-calendar .month A:hover {background:#f0f0f0; color:#666;} .quick-calendar .month A.selected, .quick-calendar .month A.selected:hover {background:#b4d2ea; color:#0056A1;} .quick-calendar .main-event DIV.clear {margin-bottom:10px; overflow:hidden; width:100px;} .quick-calendar .main-event IMG {margin-bottom:5px;} .quick-calendar .main-event A {display:block; text-decoration:none;} .quick-calendar .main-event A STRONG {display:block; font-weight:bold!important;} .date {display:block; color:#8f8f8f; font-size:90%;} .quick-calendar .main-event {position:relative;} .quick-calendar .main-event DIV {position:absolute; z-index:10; top:0; left:0; background:#fff;} .quick-calendar .banner-links {display:none;} /* Paging */ .paging {position:relative; border-top:1px solid #cbd6dc; margin-top:30px; margin-bottom:10px;} .paging .previous, .paging .next {position:absolute; top:10px; width:5em; text-align:center;} .paging SPAN.previous, .paging SPAN.next {opacity:0.6; *filter:alpha(opacity=60); cursor:default;} .paging .previous {left:0;} .paging .next {right:0;} .paging UL {margin:5px 7em 0 5em; text-align:center;} .paging UL LI {display:inline; padding:4px; width:14px; line-height:210%; background:#e7ecef; margin:0 2px; list-style:none!important;} .paging UL LI A {text-decoration:none;} .paging UL LI STRONG A {color:#d1554f;} /* Memberships */ .content .memberships FORM {margin:0 0 60px 0; text-align:right;} .memberships {position:relative;} .memberships .fieldlabel {display:none;} .memberships SELECT {width:200px;} .membership-deatils {position:absloute;} .membership-details IMG, .membership-details P {position:absolute; left:0; top:0;} .membership-details IMG {margin-left:-8px;} .membership-details P {top:70px;} .membership-details P STRONG {display:block;} /* Recently viewed */ .recently-viewed {margin-top:20px;} /* Site map */ .sitemap .button {margin-left:20px;} .sitemap A {text-decoration:none;} /* */ .feature, .image-feature {margin:10px 0;} /* My Account */ .my-account-nav {margin-bottom:20px;} .my-account-nav LI {float:left; margin-right:20px;} .my-account-nav LI A {text-decoration:none;} .account-page {margin-bottom:30px;} /* Event Item */ .event-item {padding-bottom:14px; border-bottom:1px solid #cbd6dc; margin-bottom:14px;} .event-item .event-image {float:left;} .event-item .event-details {float:left; margin-left:10px; width:210px;} .col-i .event-item .event-details {width:388px;} /* */ .item {margin-bottom:21px;} .item .item-image {min-height:1px; _height:1px; width:178px; margin-right:10px; float:left; } .item .item-details {float:left;} .item .wide-details {width:100%;} .item {margin-bottom:21px;} .item .arrow {display:block;} .item H2, .item H2 {background:none; border:none; margin:0; padding:0;} .meetings {margin-top:10px;} .meetings UL {list-style-type:none; padding:0; margin-top:5px;} .meetings LI {display:block; float:left; text-align:center;} .meetings LI A {display:block; width:177px; height:70px; background:#0E528F; color:#FFF; padding:5px 0; margin-right:7px; font-size:85%;} .meetings LI A:hover {background:#007db0; color:#FFF;} .meetings LI.past A {background:#E7ECEF; color:#7c7c7c;} .meetings LI.past A:hover {background:#BCBCBC;} .meetings LI.next A {background:#CF5049;} .meetings LI.next A:hover {background:#9D3A32;} .meetings LI A STRONG, .meetings LI A SMALL {display:block; color:#FFF;} .meetings LI.past A STRONG {color:#7c7c7c;} .meetings LI A STRONG {margin-bottom:3px; font-size:130%;} .meetings LI A .time {margin-bottom:5px; font-size:110%; display:block;} .meetings LI A SMALL {margin-top:3px;} .committee-years {padding-bottom:15px;} .committee-years A {display:block; float:left; padding:3px; background:#0064a5 url('/static/site/graphics/button-blue.png') bottom left repeat-x; color:#FFF!important; font-weight:bold; margin-right:2px;} .committee-years A:hover {background-position:0 -30px; color:#FFF;} .committee-years STRONG A, .committee-years STRONG A:hover {background:#d1554f url('/static/site/graphics/button-red.png') bottom left repeat-x;} .committee-members LI {display:block; margin-bottom:5px!important;} .upload-doc {padding:10px;} .upload-doc SMALL {color:#000;} .upload-doc FORM {margin-top:10px; margin-bottom:-30px;} .upload-doc P {padding-bottom:0px;} .upload-doc OPTION {padding-right:3px;} .upload-doc {margin-top:20px;} .upload-doc .fieldlabel {width:100px; text-align:left;} .upload-doc .file-field INPUT {width:300px; border:1px solid #999999; padding:2px 0px 2px 5px; font-size:100%;} .upload-doc .fieldcontrol .submit {position:relative; top:-30px; left:365px;} .upload-doc .submit {font:bold 90% Arial, sans-serif;} .uploaded {border:0px; padding:20px 0px;} .agenda-papers {clear:both; margin-top:20px;} .agenda-papers STRONG {color:#0056a1;} .agenda-papers UL STRONG {color:#000;} .agenda-papers UL {list-style-type:none; padding:0;} .agenda-papers UL SPAN {display:block; float:left; width:50%;} .agenda-papers UL SPAN.link {width:auto; padding-left:60px;} .agenda-papers LI {clear:both;} .agenda-papers LI SPAN {margin-bottom:5px;} .meeting-page .meeting-details {width:400px; float:left;} .meeting-page .minutes-status {width:110px; float:right; margin-right:10px; color:#FFF; padding:5px 10px; position:relative; top:-15px;} .meeting-page .minutes-status P {padding:0;} .meeting-page .minutes-status STRONG {display:block; margin-bottom:5px;} .meeting-page .minutes-status A {color:#FFF; text-decoration:underline;} .meeting-page .red {background:#FF0000;} .meeting-page .amber {background:#FFD71A;} .meeting-page .green {background:#1BA908;} /* Committee */ .committee-landing {border:none;} .committee-landing .paging-section {margin:10px 0 15px 0; border-bottom:1px solid #cbd6dc;} .committee-landing .bottom-paging .paging-section {margin:20px 0 0 0; padding-top:10px; border-bottom:none; border-top:1px solid #cbd6dc;} .committee-landing .paging-section A, .paging-section EM {font-style:normal; display:block; float:left;} .paging-section EM {padding-top:2px;} .committee-landing UL.paging {float:left; padding:0 0 10px 0; margin-left:10px;} .committee-landing .committee-section {border-bottom:1px solid #cbd6dc; margin-bottom:10px; width:49.999%; float:left;} .committee-landing DIV.oddend {width:100%;} .committee-landing .committee-section .action {text-transform:capitalize; font-size:90%;} .committee {padding:10px 5px 10px 10px; border:none;} .committee P.title STRONG {font:bold 125% Arial, sans-serif; color:#0056a1;} .committee STRONG {color:#0056a1;} /* A to Z */ .content .a-z UL, .a-z UL LI, .content .a-z-list UL, .a-z-list UL LI {list-style:none!important; padding:0; margin:0!important;} .a-z-list LI {float:left;} .a-z-list LI A {display:block; width:2em; text-align:center; margin:2px;} .a-z UL {zoom:1;} .a-z UL:after {content:"."; display:block; height:0; width:0; overflow:hidden; clear:both; visibility:hidden;} .a-z UL LI {display:block; padding-bottom:30px;} .a-z UL LI A {text-decoration:none; border-bottom:3px solid #eee; display:block; color:#d1554f; margin-bottom:5px; font-weight:bold; font-size:130%;} .a-z UL UL LI {display:inline-block; padding:4px 20px 4px 0;} .a-z UL UL LI A {border:none; color:#0056a1; padding:0; margin:0; font-weight:normal; font-size:100%;} /* Overlay */ .overlay-container {} .overlay-container .overlay-content {position:relative; display:block; padding:20px; background:#fff; border:2px solid #999;} .overlay-close, .close-button {cursor:pointer; position:absolute; z-index:10000!important; top:4px; right:14px; color:#0056a1; font-weight:bold;} .overlay-close:hover, .close-button:hover {color:#d1554f;} .overlay-close {margin-top:12px; margin-left:-12px; *margin-top:10px; *margin-left:-14px;} .overlay-content {text-align:left; position:static;} .login-page .accordion-section H3 {cursor:pointer;} .login-page .accordion-section H3:hover {color:#d1554f;}} BODY.overlay-open SELECT {visibility:hidden;} BODY.overlay-open .overlay-content SELECT {visibility:visible;} /*********************************************************************/ /* Forums */ .forum-post {border-bottom:1px solid #cbd6dc; padding-bottom:10px; margin-bottom:10px;} .policy-page {border:none;} .policy-page STRONG {color:#0056a1;} .policy-page TABLE {border-bottom:none; background:none; } .large-column .policy-page TABLE {width:545px; clear:both;} .policy-page TABLE P {padding:0;} .policy-page THEAD {background:none; } .policy-page THEAD TR {background:none; } .policy-page THEAD TH {border-bottom:1px solid #333;} .policy-page TH {padding:5px 5px 4px 0px; text-align:left; vertical-align:top; color:#0E528F;} .policy-page TH A {text-decoration:underline;} .policy-page TD {padding:8px 5px 0px 0px; border-bottom:none; vertical-align:top; width:100px;} .approve {margin-left:23px;} /* Calendar Page */ .content .calendar-page {position:relative;} .content .calendar-page H1 {float:left;} .content .calendar-page .calendar-top {float:right; margin-right:15.2038em; *margin-right:14.8504em; _margin-right:7.4252em; padding-top:30px;} .content .calendar-page .calendar-top H2 {display:inline; text-align:right; color:#444; font-weight:bold; font-size:220%; margin-bottom:20px; margin:0!important; padding:0 15px; height:1em;} .content .calendar-page .calendar-top A {margin-top:1em; float:none;} .content .calendar-page TABLE {width:99.8%;} .content .calendar-page TH {border:1px solid #444; border-bottom:0; background:#444; color:#fff; padding:2px;} .content .calendar-page TD {border:1px solid #000; font-size:90%; width:104px; padding:0;} .content .calendar-page TD DIV.day {min-height:104px; _height:104px; padding:2px;} .content .calendar-page TD DIV.day H2 {margin:0; padding:0; font-size:110%; font-weight:bold;} .content .calendar-page TD DIV.day .category {position:absolute; text-indent:-9999px;} /* Calendar Panels */ .calendar-panel {display:block; margin-bottom:2px; position:relative; z-index:1; font-size:80%;} .calendar-panel .panel-c, .calendar-panel .panel-t, .calendar-panel .panel-b, .calendar-panel .panel-b DIV {display:block; background-color:#fff; background-repeat:no-repeat; background-image:url('/static/site/graphics/calendar-panel.png'); background-position:right top;} .calendar-panel .panel-c {position:relative; zoom:1; _overflow-y:hidden; padding:2px 2px 0;} .calendar-panel .panel-t {position:absolute; left:0; top:0; width:2px; height:100%; _height:1000px; background-position:0 0;} .calendar-panel .panel-b {position:relative;} .calendar-panel .panel-b, .calendar-panel .panel-b DIV {display:block; height:2px; font-size:1px;} .calendar-panel .panel-b {background-position:100% 100%; text-align:left;} .calendar-panel .panel-b DIV {position:relative; width:2px; background-position:0 100%;} .content .calendar-panel H2, .content .calendar-panel A {color:#000;} .content .calendar-panel A:focus, .content .calendar-panel A:active {background:#000; color:#fff;} .content .calendar-panel A:hover {color:#fff;} .union-meetings .panel-c, .union-meetings .panel-t, .union-meetings .panel-b, .union-meetings .panel-b DIV, .content .union-meetings A, .content .union-meetings H2 {background-color:#00d0ed; color:#000;} .content .union-meetings A:hover {color:#000;} .content .union-meetings A:focus, .content .union-meetings A:active {background-color:#000; color:#00d0ed;} .entertainments .panel-c, .entertainments .panel-t, .entertainments .panel-b, .entertainments .panel-b DIV, .content .entertainments A, .content .entertainments H2 {background-color:#c84646; color:#fff;} .content .entertainments A:focus, .content .entertainments A:active {background-color:#fff; color:#c84646;} .union-events .panel-c, .union-events .panel-t, .union-events .panel-b, .union-events .panel-b DIV, .content .union-events A, .content .union-events H2 {background-color:#00549e; color:#fff;} .content .union-events A:focus, .content .union-events A:active {background-color:#fff; color:#00549e;} .campaigns .panel-c, .campaigns .panel-t, .campaigns .panel-b, .campaigns .panel-b DIV, .content .campaigns A, .content .campaigns H2 {background-color:#007e3b; color:#fff;} .content .campaigns A:focus, .content .campaigns A:active {background-color:#fff; color:#007e3b;} .college-events .panel-c, .college-events .panel-t, .college-events .panel-b, .college-events .panel-b DIV, .content .college-events A, .content .college-events H2 {background-color:#464341; color:#fff;} .content .college-events A:focus, .content .college-events A:active {background-color:#fff; color:#464341;} .music-drama-dance .panel-c, .music-drama-dance .panel-t, .music-drama-dance .panel-b, .music-drama-dance .panel-b DIV, .content .music-drama-dance A, .content .music-drama-dance H2 {background-color:#FF851A; color:#000;} .content .music-drama-dance A:hover {color:#000;} .content .music-drama-dance A:focus, .content .music-drama-dance A:active {background-color:#000; color:#FF851A;} .sport .panel-c, .sport .panel-t, .sport .panel-b, .sport .panel-b DIV, .content .sport A, .content .sport H2 {background-color:#ffcfa4; color:#000;} .content .sport A:hover {color:#000;} .content .sport A:focus, .content .sport A:active {background-color:#000; color:#ffcfa4;} .social-recreational .panel-c, .social-recreational .panel-t, .social-recreational .panel-b, .social-recreational .panel-b DIV, .content .social-recreational A, .content .social-recreational H2 {background-color:#ce0279; color:#fff;} .content .social-recreational A:focus, .content .social-recreational A:active {background-color:#fff; color:#ce0279;} .guest-lectures .panel-c, .guest-lectures .panel-t, .guest-lectures .panel-b, .guest-lectures .panel-b DIV, .content .guest-lectures A, .content .guest-lectures H2 {background-color:#007e7a; color:#fff;} .content .guest-lectures A:focus, .content .guest-lectures A:active {background-color:#fff; color:#007e7a;} .freshers-events .panel-c, .freshers-events .panel-t, .freshers-events .panel-b, .freshers-events .panel-b DIV, .content .freshers-events A, .content .freshers-events H2 {background-color:#8FFFA9; color:#000;} .content .freshers-events A:hover {color:#000;} .content .freshers-events A:focus, .content .freshers-events A:active {background-color:#000; color:#8FFFA9;} .calendar-page .previous-month, .calendar-page .next-month {background:url('/static/site/graphics/calendar-paging.png') 0 5px no-repeat; padding-left:22px;} .calendar-page .next-month {background-position:100% 5px; padding-right:22px; padding-left:0;} .calendar-page .previous-month:hover, .calendar-page .previous-month:focus, .calendar-page .previous-month:active {background-position: 0 -489px;} .calendar-page .next-month:hover, .calendar-page .next-month:focus, .calendar-page .next-month:active {background-position:100% -489px;} /* Calendar Form */ .content .calendar-page FORM {border:1px dotted #444; padding:5px; margin-top:0;} .content .calendar-page FORM h2 {color:#444; font-weight:bold; font-size:100%; margin:4px 0;} .content .calendar-page FORM P {padding:0;} .content .calendar-page FORM P.instructions {padding:0 0 10px 0;} .content .calendar-page FORM P.subscribe-url {padding:10px 0 5px;} .content .calendar-page FORM P.subscribe-url LABEL {display:block; margin-bottom:5px;} .content .calendar-page .fieldcontrol {padding:0;} .content .calendar-page .checkbox {margin:3px 5px 0 0;} .content .calendar-page .fieldcontrol LABEL {border-left:14px solid red; padding-left:4px; font-size:85%;} .content .calendar-page .submit, .content .calendar-page .submit-hover {margin-top:10px;} .content .calendar-page LABEL.union-meetings {border-color:#00d0ed;} .content .calendar-page LABEL.entertainments {border-color:#c84646;} .content .calendar-page LABEL.union-events {border-color:#00549e;} .content .calendar-page LABEL.campaigns {border-color:#007e3b;} .content .calendar-page LABEL.college-events {border-color:#464341;} .content .calendar-page LABEL.music-drama-dance {border-color:#FF851A;} .content .calendar-page LABEL.sport {border-color:#ffcfa4;} .content .calendar-page LABEL.social-recreational {border-color:#ce0279;} .content .calendar-page LABEL.guest-lectures {border-color:#007e7a;} .content .calendar-page LABEL.freshers-events {border-color:#8FFFA9;} .content .calendar-page LABEL.all {border:0; padding-left:0; font-weight:bold;} .content .calendar-page #codeContainer {border:1px solid #CBD6DC; width:176px; height:100px; overflow:auto;} .more-news-link {display:block; clear:both; float:right;}Xtext/cssObplist00noX$versionX$objectsY$archiverT$top""()0!12NOPQRSTUVWXYZ[\]^_`abcdhiU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1 !#$%&[NS.relativeWNS.base_Fhttps://www.imperialcollegeunion.org/data/static/site/css/sections.css*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#AD_g3456BWNS.keysZNS.objects789:;<=>?@A CDEFGHIJKLMVServer]Accept-RangesZConnection\Content-TypeTDate]Last-Modified^Content-Length_Content-EncodingTVaryTEtagZKeep-AliveVApacheUbytesZKeep-AliveXtext/css_Tue, 11 Oct 2011 17:18:04 GMT_Fri, 30 Sep 2011 13:41:44 GMTT7230Tgzip_Accept-Encoding_"174800c-89a8-4ae28c92df600"_timeout=15, max=100*+ef_NSMutableDictionaryeg/\NSDictionary*+jk_NSHTTPURLResponselm/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiverpq_WebResourceResponse#-27\b},1<EKNT]fhow*/4?FLW`  %9=Q_qtr_Fhttps://www.imperialcollegeunion.org/data/static/site/css/sections.css"#$%O APNG  IHDRdXgAMA7tEXtSoftwareAdobe ImageReadyqe<PLTEUSFlGlSWT̑w}ٞ;8iiibҕBLZpHNr'''-CC7=GPnGɬ̲a ;EMs[RRSS-//wxx4sĿ?HzbOO}ycfHHTiE{敓hæ¼򭩉y(BɰL+O4Dˆfk838E08LP̧UEū䌔1=lBvW]0Nn=;C2FC@M@syKiaV~}ADDdm򴲔%NĶmTNB/6M+w-䐑pt!F﷭׌c`슌[^HQUVvkx8_Zr㼼ġ绱xLGyx?f;D>M  䩩7GLL`-VLҒȝ@I%OihwR}[ЪwA;>L�거ϵEL𜬢ފ_-CcftRNSS%IDATxup)IT4R[[ T²,uwwμty3:s?sǝ:qq8+kp, o܈ن76n>ňzbZyc%H~yTYiRLi4hzL[*L&2'elo4żoH̸fD5fcѣ[{gڥe>֮6\hc\YC{D5[WW~ŗ/٦x~C;wv\tO: PCjj󇎦 ~S\tﺯ+j۾}}K%ǎݰg[:{zɒ u򦦦ʝ~J%Q]&Li*Xu[o<|{նmWoy;t]c \hęO"]NWB#e3^*831:/bV&.I0Cu%)-U.fF5M$^ qYc+]j6FnZ! PXqB"ɾ: ] BA$0WINJQ&NL4P-L HnY,<M$D3+}eoį}I' lG|ԟG@O8{wBR4xW_s`W΅uxEjSAt_u/-]>4ͯtW~h>l%{~3V7 G͛;sx7j 7Ŗ[^-/Qeկv?Z o|+*,+=]]=~[[[m϶]eYw%MLLLh"E; Ր4ǻ4tG=#ݣEϵNy 眑"8"I8KET]8MԤhFR]yFWPaEa< {GaƏe(撞VBžh5ߌ,͘ 5~HSZ[$B봐s=Juc_dgsLR^f=B U$Tc? ABCDEFGHIVServer]Cache-ControlZConnectionWExpires]Last-ModifiedTDate^Content-Length\Content-TypeZKeep-AliveVApache_public, max-age=300ZKeep-Alive_Tue, 11 Oct 2011 17:23:04 GMT_Thu, 06 Oct 2011 16:15:33 GMT_Tue, 11 Oct 2011 17:18:04 GMTT3137_application/octet-stream_timeout=15, max=98*+]^_NSMutableDictionary]_/\NSDictionary A*+bc_NSHTTPURLResponsede/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiverhi_WebResourceResponse#-27X^y|%*5>DGMV_ahp{} 4?_ 4BTWmjo_Chttps://www.imperialcollegeunion.org/static/site/graphics/icons.png'()*OPNG  IHDRC.gAMA7tEXtSoftwareAdobe ImageReadyqe<IDATx ŕkYlPD7T↸Q(Ѹ$:&qߒh3fd&8f4I\$NFMQlA"" ,M@oow-^ =v嫯꫺ur%P&/>XxTj.*Pz 2ӚީwP!:D@6 G8C[UPJ8&,[uuE%}KxQ泏_)Rg(v faշ cܞ~HN3y(܌I+Y>$Wxy>O o tcFߡM!i?j:0gPN nL=;>Ax%Ba6Ze@ &1L}LG?Tk*{g_k"Nrs{t |~A 3vWf>$(?ݴsBO51̜c6^jmOڀJ ̒ Va>׿Aj 0#Ch|\&h ooƇ-[<jf])4cO(9YG״i/m51 G'O5rJ @910"śr 5F '8F"ФڧG& 7)vC[: MC݅T:I!CӨfcY*#UYІE8iۼރ/]|zN#,C#p-Ա(1e u^ #M<#)JS Ϛ2f ц4ؖ׽y8SiGDABm =mڈטڥ$!jR5=5- k!w*cP3!<Ԓ}یg>=@pD8 nt ~9YВbI_IzM~NՄK$=LxҘzj9}mP;Yp.iWpX鲫l(E3l]j"ǃAc6(5˞ٟϷ§bFx>aZ#O: Tdr]mt%x;ڥ=|y~^PʔHpLߣ"aMv6au*0c $H+Xl9*ݏ\d'0s`ScxtaݩBLg*7㲠`HPiuu=#J 1e{܃Yծ#2:[^PEt0cP+Fц. hz齔 D&(Meffpsu:w${>AO:xO17'z07gOfTiC:A#cq`}_JZ 4u=p& Mk?9WT}&j70ykm̠-Ӭ.| 3RrS?6:+3sU.9aܛAsp, =k\qn|y?Q7s5 _K[`bUufC(huj"UèY(ivk\@U\EUzW<- R(]\rڪ.X:~XOn4WFm`'@O1Ca]I+ovKoB +q(?O5e T,,C}BΏ']p ’ ;zvNR] a*(=wNBtrk4qՎ 3|Y + D-fc by!Vھ\n幣"$@ieSk{ ԋ2tA]iZ{/H{DӟF'= 7eIXd>z']8ّs 7^/5sa0X$NmQҾJ w/#@xz,/*ñ7Iڴ"cn~ 4-Qt`ȄeȠjiw{Ӫ"i+ BmydZ mZ~lɟ5؅x{V$PGmFBv)%v`Z,2OqcR&Zl/z2]`A;r/;Kj뇀Tb9'zڭ}.]#޼Cx鼄69Ӊ5oٕ.{P@(.p]6 n5z1 Cڊ$_+lD#y"4o܉ȯo i&o϶3yM9Lg̝[\v *ꊏ"D=0Uh 㓨]MpxZӑzu<߾Os4q3]ʲB~a*ҭk ¸KDakB{ȔCHj.s[}C6$FgmtZҤ~}ԑ> .m[ˤL烚3)H7Fh3qN9(<6&x&Z!=}Pۀ! v^( &CbYy)6B¿m )mBIՌl`2m7E#8Yh(ۂ6J#w הХm L) x٤Af*"#`shl*d@5|~Q c 4qTѦ=El"J/  ^Pn nyifz7q%bLa?vl)AX*0~˴a׎hToʥޫ LQT֐[*B~A"E^)3}ppATjwGgNuuYZƩv'O @i:&[LXKOP_} w&~C 5rQFӞTŒ17{.{Y&aI,1vsLsŞ2)8":?Np-9fNŧu=K7<wG}(kǜm(uG5i\lq?aZkԱ{Ԋ˵e ]cڡp j`dcpFׁM"Y3IrTamJcqV ŝaM}wb[L j`F 7Kiy4x .֟hP| ,З gꄁ6BzR$}w[K{{gj)n } _[ ]㲧s{FΩĖm$]Cz-Ɨt!`"4 _J4TG~Mdՠt36pFV- $\֕Jq)'~]Qw؋@ǖya0O`L0iE,nSYx9sFh/]sb=@<0o{_g9!GZlZh6)XF˾ c2Z׷f8DԫןWN0Eo͹Еv|#fβy}pBKp߷[P·o.{UC5r E*L '>CuTJTx\-\:뙍IGJ =U+HB;Z(k=?aĈ6YHZzzHr!GpA[&v].&CTu4SԱ}vyl-]BS0bWK@]p${xVQssM&mJB)pr}SNQjs`6D#)<zED{?H+,BB5q@mPPnsM.]:BhowJ7MDgs`-7㇌','ˮdqrT/IlKg4L?ؔmAVYTQaѵ."(]v?=]\Z׿5FP[W#N+CAkUutݛ\YI!:: %=pA^|#Z-ps$kR3? ABCDEFGHIVServer]Cache-ControlZConnectionWExpires]Last-ModifiedTDate^Content-Length\Content-TypeZKeep-AliveVApache_public, max-age=300ZKeep-Alive_Tue, 11 Oct 2011 17:23:04 GMT_Thu, 06 Oct 2011 16:15:33 GMT_Tue, 11 Oct 2011 17:18:04 GMTT5661_application/octet-stream_timeout=15, max=98*+]^_NSMutableDictionary]_/\NSDictionary*+bc_NSHTTPURLResponsede/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiverhi_WebResourceResponse#-27X^y|$)4=CFLU^`goz| 3>^~3ASVljn_Bhttps://www.imperialcollegeunion.org/static/site/graphics/logo.png,-./OˉPNG  IHDR(\gAMA7tEXtSoftwareAdobe ImageReadyqe<]IDATxb?:0:͈&OlZS($ŜT9j`DJi!O+1ju^ZjI<9lR|rJFIENDB`_application/octet-streamOgbplist00fgX$versionX$objectsY$archiverT$top"()0!12JKLMNOPQRSTUVWXYZ[\`aU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1#$%&[NS.relativeWNS.base_Ihttps://www.imperialcollegeunion.org/static/site/graphics/top-section.png*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#ADb3456@WNS.keysZNS.objects789:;<=>? ABCDEFGHIVServer]Cache-ControlZConnectionWExpires]Last-ModifiedTDate^Content-Length\Content-TypeZKeep-AliveVApache_public, max-age=300ZKeep-Alive_Tue, 11 Oct 2011 17:23:04 GMT_Thu, 06 Oct 2011 16:15:33 GMT_Tue, 11 Oct 2011 17:18:04 GMTS203_application/octet-stream_timeout=15, max=99*+]^_NSMutableDictionary]_/\NSDictionary*+bc_NSHTTPURLResponsede/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiverhi_WebResourceResponse#-27X^y|+0;DJMS\egnv$:Ee  $8FX[qjs_Ihttps://www.imperialcollegeunion.org/static/site/graphics/top-section.png1234OPNG  IHDR B xgAMA7tEXtSoftwareAdobe ImageReadyqe<PLTEU~IDATxb`hI2cIENDB`_application/octet-streamOgbplist00fgX$versionX$objectsY$archiverT$top"()0!12JKLMNOPQRSTUVWXYZ[\`aU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1#$%&[NS.relativeWNS.base_Ihttps://www.imperialcollegeunion.org/static/site/graphics/top-divider.png*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#ADFV3456@WNS.keysZNS.objects789:;<=>? ABCDEFGHIVServer]Cache-ControlZConnectionWExpires]Last-ModifiedTDate^Content-Length\Content-TypeZKeep-AliveVApache_public, max-age=300ZKeep-Alive_Tue, 11 Oct 2011 17:23:04 GMT_Thu, 06 Oct 2011 16:15:33 GMT_Tue, 11 Oct 2011 17:18:04 GMTS142_application/octet-stream_timeout=15, max=99*+]^_NSMutableDictionary]_/\NSDictionary*+bc_NSHTTPURLResponsede/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiverhi_WebResourceResponse#-27X^y|+0;DJMS\egnv$:Ee  $8FX[qjs_Ihttps://www.imperialcollegeunion.org/static/site/graphics/top-divider.png6789OΉPNG  IHDR/l;gAMA7tEXtSoftwareAdobe ImageReadyqe<`IDATxlVٕ0 #԰݌7쬇 ) 䲧x+liT.\ޢclr{ :K_}w~W"@n=Ǡop٤^)%n躌G" [YX0͙1+[Ɨ.jq6(fX1z %iɂ ;mϽ!% Cء]P,,;mɊbJzqp?t/ }@m%L xZ%Ofx oݬ͸F *9 #R͋h)M-*1A8649sٛdƴޛ겂YZEfڝf~yş͍bHl9^K&m, j!Y[2KPLb`KYpYB|ISN.ϼVyī B)YON?9Hr(؁Hc\.;?L`dR\g9(RughvL` J] WnYx%5ԉBifef;W]5{yH>C e3ij c['reл(Y `;a^\v߁JLڼc8P`쐱\%L<]Ǒ3pVRQ8? ABCDEFGHIVServer]Cache-ControlZConnectionWExpires]Last-ModifiedTDate^Content-Length\Content-TypeZKeep-AliveVApache_public, max-age=300ZKeep-Alive_Tue, 11 Oct 2011 17:23:04 GMT_Thu, 06 Oct 2011 16:15:33 GMT_Tue, 11 Oct 2011 17:18:04 GMTS974_application/octet-stream_timeout=15, max=95*+]^_NSMutableDictionary]_/\NSDictionary*+bc_NSHTTPURLResponsede/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiverhi_WebResourceResponse#-27X^y|*/:CILR[dfmu#9Dd  $8FX[qjs_Hhttps://www.imperialcollegeunion.org/static/site/graphics/button-red.png;<=>OPNG  IHDR QKgAMA7tEXtSoftwareAdobe ImageReadyqe<|IDATxn8@*盗Ʒ*c:DJ ќO+HEJn;ɟ*u]%ܼ.^>6{|0o^fں߬}oisMl=۟jXB m*weM%v/5{;Z2WXyiܧfqKa6\gbqY5#?'?"i^aR{9xMWC %.Y,}`|Ĥ_~6Y@jX&_^Ŗ2I1kqlBݭk܇kmbO}1 9oL-԰YebX ~? kz Q\0l2KK}S%~񰾮R5n\60b/}T(īeUx6e:$N}5ZϮˇi[̌e&t1nnY kX^l}/D:ca8r(ciU~_>D0'6'8ٙmda@:FxO_8| /Ml#}g) y?gi_%Qn" L)_28)$nay* V>t|ljv nɍ#9ű3{t]ibRm0X`j7Ɨ-|UjPjxa5tyRx}ǽմ63HMr֙~cuTK `e}'%_JV kZ:Kم̲X4n/a -nru/>~_ۙx1C Ki.M~.}KuNO2$LsN&ĹKޒBke^tq Np1TZ}\Q,59drRÓ0 ;? ABCDEFGHIVServer]Cache-ControlZConnectionWExpires]Last-ModifiedTDate^Content-Length\Content-TypeZKeep-AliveVApache_public, max-age=300ZKeep-Alive_Tue, 11 Oct 2011 17:23:04 GMT_Thu, 06 Oct 2011 16:15:33 GMT_Tue, 11 Oct 2011 17:18:04 GMTT1258_application/octet-stream_timeout=15, max=94*+]^_NSMutableDictionary]_/\NSDictionary*+bc_NSHTTPURLResponsede/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiverhi_WebResourceResponse#-27X^y|#(3<BEKT]_fny{ 2=]}2@RUkjm_Ahttps://www.imperialcollegeunion.org/static/site/graphics/nav.png@ABCO׉PNG  IHDR \MgAMA7tEXtSoftwareAdobe ImageReadyqe<iIDATx A~Qk:㸃S@԰04th5cpדL!m=Gy(O,C#3W̲nT |U+L0:IENDB`_application/octet-streamOgbplist00fgX$versionX$objectsY$archiverT$top"()0!12JKLMNOPQRSTUVWXYZ[\`aU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1#$%&[NS.relativeWNS.base_Ihttps://www.imperialcollegeunion.org/static/site/graphics/nav-divider.png*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#ADً3456@WNS.keysZNS.objects789:;<=>? ABCDEFGHIVServer]Cache-ControlZConnectionWExpires]Last-ModifiedTDate^Content-Length\Content-TypeZKeep-AliveVApache_public, max-age=300ZKeep-Alive_Tue, 11 Oct 2011 17:23:04 GMT_Thu, 06 Oct 2011 16:15:33 GMT_Tue, 11 Oct 2011 17:18:04 GMTS215_application/octet-stream_timeout=15, max=98*+]^_NSMutableDictionary]_/\NSDictionary*+bc_NSHTTPURLResponsede/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiverhi_WebResourceResponse#-27X^y|+0;DJMS\egnv$:Ee  $8FX[qjs_Ihttps://www.imperialcollegeunion.org/static/site/graphics/nav-divider.pngEFGHO5PNG  IHDRw f\agAMA7tEXtSoftwareAdobe ImageReadyqe<PLTEZFභ e;U{Qw/V7ޥ/_»>˔7E˰7u9 9(/;nW *B}gTJGQԐvc徿{z{Jդ3X-ڝwϴvu{:,.|e7b1oGىnKsrڳh2hT=EijeȌdpqq_9ٳ7쁫䮻S԰K0zL7ɮZHuΏT-djI\ńI7ˡ`߹*Qԯ|n|=unfb^uW@8*RLMү%ž;pZSԒcLQr,u[G3Ԙc`bcpǕTMn}n\& γwzֶy=ʅ}22BIDATx}@TWaJaA"ͥRDAP{DGMMuSw+yo@̷I 3S`cxs9  0zg@w^ԋ {N<"q~m{=a-w>_|e}RGఁ7t~z^ϙ `=Ş+g{=_4pOpz?|C߁臍E$̑GaM%dmG %,xL 32qzȂڍqg&vOC=’;n0fdeaex D <8^V{z;y ?1㐂H6 S M9zHdɑA&"EoP$e&,=aorV۲Q ڲ'12cL$VrD\T ;2VIQhDм+b]o $V|e҄k(YyyU@d9-m90pst襫 `kbV8 A` LEQF\tBLG6xt!0BHA "]^!;@+W\'ÐHpۼAzhʊb4m6=ALtmZe:F&Q_K=2/13((3s'P_d\I _)2t„ے~s0>SEG/@>_O RSZ{;qI@~J3yf:ԃiԼT|ƺPբڤ>k_Y,PAۺ<ԉmU1<5)GM`j n DQS c•T+r 8JأsAC:򎻎hvK=n|>G_K(*Sq뮧oH d0ќKb 9C  x͖49=/k4;e4؍HQuUAA˽^>6/j >)0Qt|XH rU 6N<!/PK`\$N4"N( 0SFA@j 8(~ӸG*urOC8C>&v>U(߫\PJC'H$1%&A6MΕh )_Í&cK6gNjP͞q9%ƭaU[T^ A%RɝN-y̙3T*uwVʁ w iv&?8;IaQyJ. PKJG~X×[] sa}t&0"Fc7n MW6E%~箝z ܯaX60Z;>U}噦ÿ8$\!R%T]fd9EbNjɉ]casan[A[@Oaӗ4hUnjða1xaqz!d!2aSR₋ 7HKYswOfN,,h *'`6yyń;"dx# jwnqHHxjMfiYCS1Em2}wXRƎM2oKWƸOGR3^ԉɼ2X렡{{Cd;zQk yLn!,ԏ/)#%q$餘H I3KTJ7|胎~;y; t? kn3g/$1W|8r*}ߢca`{s E7D'_Vb^tP? xԇuA* 1JʡʓJtER&YxqHT &F󶿱w6kLƖd yI%WjKLͧN>5|gUKT%^p;6gJuLTlp6un뽥KzX&lO ,a[wx/F:om pH*pt(9?6O_G9yG8I jJnt첿tdY;<~&:P":<㼳VZ CS 1eZ~1:3˒*eC_S_ٛ вZCS!Z4Q^w5d#RHӔWBnF6nuNncʛO==$=Z2aHE,5/K6^E]+I+!:LquEXݳ$詠tZ\*#xi6V:gӮ@睥=^B=p %씵 EG(`H!.w~f6K}ɕ%Ɏ] (_p3 BO`>k Jy7N|Pvlػ==_-SZyg0OO*'G ]Z w4~jUiis]M-"MiV[469)73rYm𓔦^*UJ,D^ ڀGZ ;Sl ;I `+>° ߕ=K؉Ȓx+ FX Γ~ S<x-<עWW$ Xi\+%"}%WT"y7 טS.[y"rIBnxh)?^Z͛;#W5╧ bHL-PAoEp\Єg'M Z2|DV5&դcON0Q/j {7a)e/!ʅ zVڗ~ UA VRqVTVGPbŎȄ TCP%yS2(adϬ,O9Wە J_8Në{[ٔt)Nwfq)ayg_0)g#!vɠ^JJ}F".vt#UUNt@݃J]k/`(m\U@ *KuB"'qQfX"#'tXVLj4h,͓,]+gahD=ݢҞ7~՚t^Ri#GFnѪ`&t3TۥWuzH;"~Y?nW‚S:XX$YX4K&.AVۂj]Γ#L cG,vI,]`*oqݵg'WQс>Sgq{rqꑎK+ R aEcN땏rR( P┡1ӑʃ,^,<0I] R=rDZ2J4F1\di:55+Q !@Y1/4neIIIq/I8i~ryv&6 {3{3[Kvԑ>Hb?]$ 2_Z.?iY'wĉ1~)s> }GKcP:P]feDX]*}$ j[uք,}}ر}wr=&z^tSȭstiԉ:ovޘxv/ @B8w]VN+W!;Uǯ}c7\t?f1}-*9`TўP݈.vlG;C(%U,!kU{s\qRX:ʉ2ho-v߁=DiW'Md2k5]К KӪ^/%̟/[*lrU:DJuڭ[5C5tLs7K9Vne=MIH<)aT4E 'q'/lH1^!>Ps&bBdO`)aB_."n~?P:n>k}3 z# {ށz _Ŝhg߾1)$h)nP6kjFS/-j##auRDy$!աx((QFjl|RKC:dСKJ2(%Bgz>}ɫ#hїd@D:Cn1tv'R+A2XnaL -`}_X +< /dw"?Iw [Cg~I/H8 ,<'~PAQ"uܸ>usZe&cHvxxH'nU~m~PZIܖȓO&,H-25j6\b"|mm)Jl-o;lVuvav].S+0P<igL=xi2amQU2!65v[I'P%k+Ap^JKoʮqmlj4Y^}Z]!Ă :$QMH/Y℠Q_&qIf9)l̉׆I}`^uq MأOVwڅ<V7UlD C`V RaUSRWކt]DtP LO FW̛`!%ݾK+aK0l T߫M0\gvBtg/ĊxF&zb%ʨM ,66Mm9)th?IL/_|YUKTA7QnʜIraaquFX 5ԿZ튧c+VЊ40"ᆽtyݛ#F1ajf疵,~fݚsH45*Ҍ@5Vk^phɒ%?%?XlfҡC.PI jX,{`ٓuzCN,ςNk_]RI ΢߲r=TĠGIF-K;4h(~QߘK%7_O'(#UԖy6Z$きݰ{_օYԋf#~ K4ehH]ƦdQ–wu]A~Vd |k32]A yUNCw?:XI|x_67}>+OY ̰$/4z)u^={ǦAD|ONsppx2Y7pwA݅9kP}v*ѻi )0 H8#ᨅ-I{-H(%d6VZTW",iC%>]-.4 vIQ3g>?sY90(f@ o4KkӝTudkV7!98 ?~5W~>5YZ7&ΫO;.n3, ,կ@(cICᴟCN)N?{-XX/=#P>6 O4 @9!*4v5(-vb/1{`9 r$b1~R\l|Xv|ԨWf U( n.'J!!Z>E[-|w)vΏxg;& 0SjZX7qF{88AXMa+}vNv1R֥w&Sk3Ͷ>(as_xi>ݴULqN|wr3t/PnZ흾Ғj\ w: a+qekjK)`4 |X$Db{.@ >r v#_lHaIBa5p?~۠nJ]Qٓ-&|rz9q_L|Lz[w?777s11ynW>Vmb^{I!{VuuJȏ*s#vNg[;%By}m5eάmM;_i %ߦmn[L:i1KPED  u7D\4gBk PEHX[!SBk‰P=H\B㉏[켉 \x,xK/*eo*.6o9ei* ,a~:9&=[6-u 7ư9*ؾiC%?C {TF'B< `E(CXOEyڰ2J:]5=8ģ0(#n ׭zSFD8y&$SYZqqًئ('~6z?j͘Fn72uҟ͛p  kIki5OޝybC\D &?s9TyrbALAKg.[gxܥ x,P?n|6Z# *mOݳ<?JXu_*xj$-䲻w>=,PXQJWAV$I _!6ɯ+jy"ٯN}u$失U0W`m12X[^Q*vnFgET_rv{v['UEi&jbgƊqH.yMNג 4 <XZpS32<%X!\k;P{"~{jYKÛoJ;s?%f"P [H*_~s=#;")g}V,s%]LjAj/7 ^3w/1sYTSshwZ㭏);WDsmNn[>N*l1͟&JHR6edQ_v\3uJVMťWP`o12ӪS*qTlIAyy+A)5ow1ߓzNw4/?MX*10Zl\hP$hVONG?)DO Eh͋8Fd^*?6+<]佶$E"/df/n{'V00000000000000000000000000000000000000?c``xd1G ?!TR}IENDB`_application/octet-streamOsbplist00fgX$versionX$objectsY$archiverT$top"()0!12JKLMNOPQRSTUVWXYZ[\`aU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1#$%&[NS.relativeWNS.base_Jhttps://www.imperialcollegeunion.org/static/site/graphics/footer-logos.png*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#AD3456@WNS.keysZNS.objects789:;<=>? ABCDEFGHIVServer_Transfer-Encoding]Cache-ControlZConnectionWExpires]Last-ModifiedTDate\Content-TypeZKeep-AliveVApacheXIdentity_public, max-age=300ZKeep-Alive_Tue, 11 Oct 2011 17:23:04 GMT_Thu, 06 Oct 2011 16:15:33 GMT_Tue, 11 Oct 2011 17:18:04 GMT_application/octet-stream_timeout=15, max=97*+]^_NSMutableDictionary]_/\NSDictionary5*+bc_NSHTTPURLResponsede/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiverhi_WebResourceResponse#-27X^y|,1<EKNT]fhow #*3ITt,0DRdg}j_Jhttps://www.imperialcollegeunion.org/static/site/graphics/footer-logos.pngJKLMOnGIF89aZA\\M{[[M\\N|K(ffY|qqeþ||p۳J(֭ľɐppdĿ{{pnSJ'ggY}V6̹ppeaD!,ZA  ' /   ))) - *  *7 * 쨲%0A4a@D%\X  L8B( AZt:$@J^ HA{^,xqJ Hq-HQC5&ơ Jp"X``%X h!4Cx UGm!逯R"=W9[ l۩YB02ޮBnt1 DYG VTG Zh XX,K ,YfuC(!ƿznL0 xO^)d鐠P7Z "A 0@/@fK⍕H! lrV{ g/tVK9 H&PAǰM ]C-,TA=8!pN @$,PPTiXf\v`)dihlp)tix|矀*蠄j衈&袌6hHL N8: N(@@(!4'H*#:Bq |p<Hl0@ @pH#5h@4D-4p<ó`@h,(!K<|Q P@Ah ` !Aȇ00P@E[@ >xPs04@> @ !@2`X @zp4,. h?P!(=щp$~ f.\#2$0B 3_@o8ڄ4͊;xոH`z?pٷ]@t΀ޖ96@ڹn@ He# l,$̢x0D"#08 ATλ{#h<K[4@ x@cIZPȅ A tCB[ F 2*߭m$ ` $+ | @`CʊQ>r]QD!V.. ;VHG;Yimage/gifOWbplist00fgX$versionX$objectsY$archiverT$top"()0!12JKLMNOPQRSTUVWXYZ[\`aU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1#$%&[NS.relativeWNS.base_Hhttps://www.imperialcollegeunion.org/static/site/graphics/othermedia.gif*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#ADm3456@WNS.keysZNS.objects789:;<=>? ABCDEFGHIVServer]Cache-ControlZConnectionWExpires]Last-ModifiedTDate^Content-Length\Content-TypeZKeep-AliveVApache_public, max-age=300ZKeep-Alive_Tue, 11 Oct 2011 17:23:04 GMT_Thu, 06 Oct 2011 16:15:33 GMT_Tue, 11 Oct 2011 17:18:04 GMTT1646Yimage/gif_timeout=15, max=97*+]^_NSMutableDictionary]_/\NSDictionaryn*+bc_NSHTTPURLResponsede/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiverhi_WebResourceResponse#-27X^y|*/:CILR[dfmu#9Dd(6HKajc_Hhttps://www.imperialcollegeunion.org/static/site/graphics/othermedia.gifOPQROPNG  IHDRHgAMA7tEXtSoftwareAdobe ImageReadyqe<IDATx\OQC!+kgɎ혏N# `0;2&CSdE_ 1YL.w#TXo@jB]iQtnZl]:z9$ܢ3\ $Ov۬-(7SnH^OŲ<ʽ(-CuҼ=R^_CIENDB`_application/octet-streamOhbplist00fgX$versionX$objectsY$archiverT$top"()0!12JKLMNOPQRSTUVWXYZ[\`aU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1#$%&[NS.relativeWNS.base_Ihttps://www.imperialcollegeunion.org/static/site/graphics/button-blue.png*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#ADu3456@WNS.keysZNS.objects789:;<=>? ABCDEFGHIVServer]Cache-ControlZConnectionWExpires]Last-ModifiedTDate^Content-Length\Content-TypeZKeep-AliveVApache_public, max-age=300ZKeep-Alive_Tue, 11 Oct 2011 17:23:04 GMT_Thu, 06 Oct 2011 16:15:33 GMT_Tue, 11 Oct 2011 17:18:04 GMTS272_application/octet-stream_timeout=15, max=98*+]^_NSMutableDictionary]_/\NSDictionary*+bc_NSHTTPURLResponsede/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiverhi_WebResourceResponse#-27X^y|+0;DJMS\egnv$:Ee !%9GY\rjt_Ihttps://www.imperialcollegeunion.org/static/site/graphics/button-blue.pngTUVWOo/* Content */ H1, H2, H3, H4, H5 {color:#0056a1; font-weight:normal; font-size:160%; margin-bottom:10px;} H1 {font-weight:normal; margin-bottom:14px;} H2 {font-size:120%;} H3 {font-size:110%; font-weight:bold;} H4 {font-size:105%; font-weight:bold;} H5 {font-size:100%; font-weight:bold;} H2.section-header {background:#e7ecef; color:#0056a1; font-weight:normal; padding:8px 12px; margin-bottom:10px; border:1px solid #cbd6dc; font-size:120%;} H1 A, H2 A, H3 A, H4 A, H5 A {color:#0056a1; text-decoration:none;} .content P.title {font:bold 110% Arial, sans-serif; padding:0 0 10px 0; color:#FF2C0F;} .content P {padding:0 10px 10px 0; line-height:140%; font-size:85%;} .content SMALL {font-size:90%!important;} .content H1 SMALL {display:block; font-size:60%!important; font-weight:normal; color:#999999;} .content UL {padding:10px 0 10px 30px; font-size:90%;} .content OL {padding:10px 0 10px 30px; font-size:90%;} .content LI {padding: 0 0 5px 0;} .content UL LI {list-style:disc;} .content OL LI {list-style:decimal;} .content UL.reset-list, .content UL.reset-list LI {list-style:none; padding:0!important;} .content A {color:#0056a1; text-decoration:none;} .content A:hover, .content A:focus, .content A:active {color:#d1554f;} A:hover IMG {opacity:0.8; _filter:alpha(opacity=80);} .content TABLE {margin:0 0 15px 1px; border-collapse:collapse; font-size:100%; width:100%; border-bottom:2px solid #D3D5D6;} .content CAPTION {margin:0 10px 0 0; padding:5px 5px 5px 0; text-align:left; vertical-align:top; color:#0056a1; font-weight:bold; font-size:110%; margin-bottom:4px;} .content TH {font-weight:bold; padding:5px 5px 5px 5px; text-align:left; vertical-align:top; color:#000; border:1px solid #D3D5D6; border-width:2px 0 1px;} .content TD {padding:5px 5px 0 5px; vertical-align:top; border-bottom:1px solid #D3D5D6;} .content .even TD {background:#D3D5D6;} .medium-column .content TABLE .image { margin:0px;} .content .image, .content .image-left, .content .image-flush-left {float:left; margin:3px 10px 10px 0!important;} .content .image-right {float:right; padding:3px 10px 10px 10px;} .content .image IMG, .content .image-left IMG, .content .image-flush-left IMG, .content .image-right IMG {border:1px solid #cbd6dc;} .content .image EM, .content .image-left EM, .content .image-flush-left EM, .content .image-right EM {display:block; padding:0 0 5px 0; font:normal normal 90%/120% Arial, sans-serif; color:#666;} .content .image-copyright {display:block; color:#666; padding-top:5px;} .content .summary {color:#666; font-weight:bold;} .emphasis {color:#993333; font-weight:bold;} .content .time {text-transform:lowercase;} .content .align-right {float:right; margin:0!important; padding:0!important;} .content STRONG {font-weight:bold;} .content EM {font-style:italic;} .content ACRONYM, .content ABBR {border-bottom:1px solid;} .content SMALL {font-size: 0.8em;} .content SUP, .content SUB {font-size: 85%; *font-size:95%;} .content SUP {vertical-align: super;} .content SUB {vertical-align: sub;} .content PRE, .content CODE {font-family:Courier, "Courier New", monospace; font-size:12px; *font-size:1em;} .content PRE {overflow:scroll; margin:0 0 1em 0; padding:0 0 0.5em 0; white-space:pre-wrap;} .content CODE {color: #f4eb5b;} .content .link IMG {display:inline;} /* Special links */ .page-links {margin:50px 0 10px;} .page-links LI {display:inline-block; float:left;} .page-links A {padding-bottom:10px;} .page-links .facebook, .page-links .youtube {padding-right:30px;} .button:hover {text-decoration:none!important;} .special-link {display:block; background:transparent url('/static/site/graphics/icons.png') no-repeat; height:1.5em; text-decoration:none; color:#333; float:left; margin-right:10px;} .special-link:hover {text-decoration:underline;} .rss {padding-left:37px; background-position:0 0;} .what {padding-left:18px; background-position:0 -100px;} .share {padding-left:21px; background-position:0 -200px;} .facebook {padding-left:19px; background-position:0 -300px;} .youtube {padding-left:22px; background-position:0 -400px;} .arrow {font-weight:bold; padding-left:12px; padding-right:12px; background:url('/static/site/graphics/arrow-link.png') 0 5px no-repeat;} .arrow:hover {background-position:0 -389px;} .more-events {display:inline-block; margin-bottom:5px;} .twitter-link {display:block; height:20px; background:url('/static/site/graphics/twitter-bird.png') center left no-repeat; padding:0 0 10px 45px; margin-bottom:20px;}Xtext/cssObplist00noX$versionX$objectsY$archiverT$top""()0!12NOPQRSTUVWXYZ[\]^_`abcdhiU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1 !#$%&[NS.relativeWNS.base_Ehttps://www.imperialcollegeunion.org/data/static/site/css/content.css*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#ADu3456BWNS.keysZNS.objects789:;<=>?@A CDEFGHIJKLMVServer]Accept-RangesZConnection\Content-TypeTDate]Last-Modified^Content-Length_Content-EncodingTVaryTEtagZKeep-AliveVApacheUbytesZKeep-AliveXtext/css_Tue, 11 Oct 2011 17:18:04 GMT_Fri, 30 Sep 2011 13:41:44 GMTT1428Tgzip_Accept-Encoding_"1748004-116f-4ae28c92df600"_timeout=15, max=100*+ef_NSMutableDictionaryeg/\NSDictionaryo*+jk_NSHTTPURLResponselm/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiverpq_WebResourceResponse#-27\b}+0;DJMS\egnv).3>EKV_ $8<P^psr_Ehttps://www.imperialcollegeunion.org/data/static/site/css/content.cssYZ[\O N/** * Forms stylesheet * * Generic styling for form elements, including text inputs, radio buttons, * checkboxes and submit buttons. Should work for both hard-coded and magic * forms. * */ /* Forms */ .content FORM {margin-top:20px;} .content FORM P {clear:both;} .content FORM P {zoom:1;} .content FORM P:after {content:"."; display:block; height:0; width:0; overflow:hidden; clear:both; visibility:hidden;} .content .fieldlabel {float:left; width:155px; margin:0 10px 0 0; font-weight:normal;} .content INPUT.text, .content TEXTAREA.textarea, .content .password {border:1px solid #cbd6dc; background:#FFF!important; width:280px; padding:2px;} .content INPUT.text, .content TEXTAREA.textarea {border-width:1px 1px 1px 1px; border-style:solid; border-color:#cbd6dc;} .content .yui-gb INPUT.text, .content TEXTAREA.textarea, .content .password {width:206px!important;} .content .short-field .text, .content .short-field .password {width:60px;} .content SELECT {border:1px solid #cbd6dc;} .content .radio, .content .checkbox, .content .checkbox-option {float:left; clear:left; margin:7px 5px 0 0;} .content .radio {*margin:4px 5px 0 0;} .content .checkbox, .content .checkbox-option {*margin:4px 5px 0 0;} .content .fieldindent LABEL {display:block; float:left; margin:3px 0 0 0;} /* Labels for radio buttons */ .content .fieldrequired {color:#CC3333; font-weight:bold;} .content .fieldindent {display:block; padding:0 0 0 165px;} .content .fieldcontrol {display:block; padding:0 0 0 165px;} .content .fieldcontrol LABEL {font-size:90%; margin-bottom:10px;} .content .quiz-page .fieldcontrol {padding:0;} .content .fieldcontrol BR {display:block; clear:both;} .content .help {font-size:90%;} .submit, .submit-hover, .button, .action {border:none; background:#0064a5 url('/static/site/graphics/button-blue.png') bottom left repeat-x; color:#fff!important; padding:5px 8px; font-weight:bold; overflow:visible; cursor:pointer; text-decoration:none; zoom:1; position:relative; *top:3px;} .submit:hover, .submit:focus, .submit:active, .submit-hover, A.button:hover, A.action:hover, .selected A.button {background:#d1554f url('/static/site/graphics/button-red.png') bottom left repeat-x;} .button:hover {color:#fff!important;} .action EM {font-style:normal; font-weight:bold;} .continue-button {margin-top:20px;} .submit-form .fieldcontrol {padding:0!important; margin-top:20px;}Xtext/cssObplist00noX$versionX$objectsY$archiverT$top""()0!12NOPQRSTUVWXYZ[\]^_`abcdhiU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1 !#$%&[NS.relativeWNS.base_Chttps://www.imperialcollegeunion.org/data/static/site/css/forms.css*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#ADm 3456BWNS.keysZNS.objects789:;<=>?@A CDEFGHIJKLMVServer]Accept-RangesZConnection\Content-TypeTDate]Last-Modified^Content-Length_Content-EncodingTVaryTEtagZKeep-AliveVApacheUbytesZKeep-AliveXtext/css_Tue, 11 Oct 2011 17:18:04 GMT_Fri, 30 Sep 2011 13:41:44 GMTS903Tgzip_Accept-Encoding_"1748006-94e-4ae28c92df600"_timeout=15, max=100*+ef_NSMutableDictionaryeg/\NSDictionary N*+jk_NSHTTPURLResponselm/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiverpq_WebResourceResponse#-27\b}).9BHKQZcelt',1<CIT]}  48LZlor_Chttps://www.imperialcollegeunion.org/data/static/site/css/forms.css^_`aO{GIF89a]+u)nqoѨ*굓+.,0ʹuhS*׫-,hroǹMƗltvuuNSqsOH4N3*fUT.KȴܩyjͫVǙq7膶TE*弯sVJ,pC۵h92ӭɆzдŻ83AIƝxb(ؔ0歒IÛ+EDEhXnҌ̥l[ͷee}feeɺțp9DiGCXٻL$WVWycMIKi+V)׫Įԗ# %#LZDBxcbɩo|1SRU%X^yUw6l',s߄=a|gwqPXG[,5vܴ}m{4ޗಞ0ፏ ;P_ޤ/,疼Ѷmp|FŴZFʚ \QB¦~+޲NO]   ꊎXe`Aɾ"4壐Ӫ0pdC0~}|z(W"Ң#ӎuu!,]1Ā#@ TSxġ@ -ba0 ^(Ёd /ZL`E$h#'6w B;"$BR\ٿPJJիXjʵׯ`ÊKXX˶-۩nʝ;wZx'O7ܗwW8̵XV!~#?}N ˠ7AndSZ&;Elzz\jg/l[EC57$֏$yЋV $&[ޔ$ d hD"6Ylj` }77ɉs쇩DYn(1Es_Mw#h~p9DlS'IJZ,&3Yst֩/ s̶do  h*qc4 LҀ90;836[)ZKk_Qr9o9@2ҋcl741@c9GEҐt@Ov+s#>973rC]E?MΎebr7J0w*OjAЂ@R7@:q,= 9T63o>/ȉĵ$2!פ"[p%AZs @ٙև4Yֶ/[ hSM@hHuciω<,3[8؇.P hGQytJ;V.2*y<" pMAJx72K Fr8C VV цSbۛ Ƌ% 6%8PæukMd>kȲ-0ֺ;k6$V3;XSx+[6)tmq6FKB=-jSV6)UZVg6`x G l04i(fA]AtNf_ ! K PS˕yوFx6U4TdZ|ga$EV5~iVH3 ?=&@ {1ha',|խpFzYQFяbNf;ЎMdζd? JH]&A4` WIʰݲ̊_(X /3BD!0" N[fd*ea*'KEP4i nj5K[b/F c6GR _2ŋŬ[@M<0içz΃~֜cvAŨ4[sGXfD?Lo12tpnkx; 8e1 {5a;8c&#+20vE!4x a0$ r1T rƜ1kt\zяY?q+}N/bEk7lVz fw m~7n0`x`{`&h 0R'oWJ4@ oyy$,  Qi  iP "p(Dg8~p  耪؊8c}I0}P{Ppu`H,c;3@c$ p oP gzI<d\5] P P0 qU"'@Vt "P6r.s<3sV~HPБY Y"~"yH~wɒ, 07&9XOwUDYƊFtW4n4 `%8XhX{WU,x)WpB+RD6y4H,` `H=Ǘ"d3Zp !E@i\CEC< ] /0ez&w@QbІM<| v_2}0ا?"YiY-;,9  ~HW$-y ĩyhJlH9macP`èu@7Pp؞uAUvWP]j)d++3:4E%`$)P%  rp lИ@&,iqe_%P= d|60W^<,R$s P`% @K\Kd0_A<{-t5S S|[\ ,wP Y}[ [˯}jqKpȫju{wj+;sj{0l:9`l^P#plL@8̿ۿ+ h& l^@N[l \oGNPupe+` TШ@Qp&l o{^[萷W$};f5( !KS3=ofy@/6`eo>@p@@U, fJ \ ",@;p U2em1, !Tʇpw: 0s۽;Kի՛[kJ[ʥ+˪Lɑ ɚɱ|K; U@+̵<&;p 6Ȯ@5mJ F&5Kל/60l\l9@O 9⼿$#< @g[ 7`T`(PQeyZ 7ci{@6C3=2f}[ĄX<5R*"o "pS5| g_y_P0M3q_ L}l}hkɹ pgv1@l u1P =]_1ptחpؔٛؔ}1`ʚڝ  Gڦf(@ۛ ]˖<غ ɤ ʜl̲J{R@0m^Pl/;l@ml(ņ\v =< PT 7@p`` 3p( [ Yp1"I\ӿrqN 6^ӣ,0 ,6 % cx @p+|8 зmQT=c\޺-NH p׍sN۰=w pL` p~ 1n s ջ. 鍎 ` ]>^=`~~l̀pv --}ܨʖծNlkl}ll SmlPl zJ=!pX`[X`pT@` %#6|` 9Lmy#+;] zXh-Ey5E5 %i0ir$ZR-$#xTaڂ;P ʤ)m? 嚺nȎUUu~> (P5ps u }κ P5 ^Uo_ɧ_U0n }l\lĎweP`ҧPl ц^9 @[ҞVLZp lM;{`ʔ_ `| XÇXE?;$YI#y̐f B T B 4a9`U,7, 4cry@W4%J.]1%^Ԩۢb%  8Pn<-ãU,$x%x% Z"2 H4 1 PhBil P1|)CORYW/$ gQF<o1-˿QiY}u 7_< d?~d]Bqcb >?y`%b?'<8>R)A+Njp‹? g6= g6`C )'P`Eƒ S)'!,{"{ >*zR 0ǡ~BI#TI(l!dz@L ?;̈3T"4?!T B,NSΓ/Gs+~~0(LD1:%/<\?-Du􇪯H C=gJ@"8-:(%A?~29pD84(MmP(w q PAڶ%lT,Qi׸˼ i#zF`-M?4 as!MyYwJPTa}ql>JrJfMۡJ" %q/Q'Dbuӝ̈2!@F1)T^:JT/% (E)5 ^,DhSr{< 38)j Z(Tb@p@.tp5pEV5gx hD $,n G G"b @B&(a J"McF4"$BcghCAb1'.oqMHFv;y3? @2F*QՠA+խf \xRwLg-‹ Ɔ#9\>8Qo-yF"y.\ =QU/FuDyO0<ҀѡwDyyqC ,P>Ƈ:"H4ũ.}i#@.ctLg[Da!,S &CPS\K\rf,K W Q@_-mݠb1j3P]ke/&=ѯD|; 63rx7 rlDYd,f;/ QDJP c@ycwNW}mkBG8RY 2n&}VړLe{#RroA@^)$ކ?@&4w @C@Ư'=SL >;0@TC0~_$Ix;"ZH`KdD]x=v-k[- pڲ3zXBi2ng!Rc:PuسAZ}YC! /m$4__B, 3c63\/j԰e.[x Ht!`Ww0bKP  vXN#8@[egݭnCP{nǑU ecHsS冮9j~)c 8oow}0`9A8`ppTP>o>훸8'°)0p99cC,AΡ|*;(!:R湈ˈÈ*H1r:p'c,lV:e:3 B[0*{`ڃ:`"w (=h,DlDW 2C4z60<0/(wyͻB'r?,h hAAh=,p,h6Ѐ0ᳵ/XIHa#@jfBf{f>lk.rYowX88kpU<}3 ̤ ob7@+#&~%6q. kF<F;$۹ !ۺ:t'A :M $LŒQ{ܹ-TcIh3$ xZC i@1Hg[*|K*(w6W]7h 4Ac惋J`$Gj.oFps'SppCN~4oG p[`P.`rFФ3`L$o&x|ϋ4A!~yypZ 9kIlu Ђ: -h??KѐʊGa#Aюh:)̈x*+ʬ<@ *芷:Tòt ̲ 9p=hYѻ::*`@hEdĴzxy1FyAL "r4DO("F[i?j7ɸ,hh+Y>8 Ŷ@P=#;یAGM氙ڂF3N_nNa6pƂ_H.eOI PPz  mo(pO+&7y%䲏C( n[{`}2`x&vȒ lAt"w/K8]&ݤ> ّ3ʩK00KX1,`Xp@P:I3'JVF9: -+*/-K2f| Yyi|x; pliEEmFit2 Ѕ.(ZeX'Ip`xY"]1sټ L,B,дݔa{@h %p| g |%^_HqxN,UTt,O"Ppjox^H 8<K]ފDPt@p_~X/)p',`$$( `0RA3Qa U`/A-"9#Cң'ŀ&R.)/T[ 2 & RH˟ |0wp %۲ DD*&{0,h+u ;`[-cU_PppJX\ WRP/8Ќ%` @ho ӥ-k3p 7OGHxd5ukgrua8 FhY{6"o`H|BvڧR0(KS(R+r[`ү-m!S|PCD-y \p16{r:<`.Ng%R"\ `xfn`D>1r-`؀ HIaKPvD/@lER6Vn]uֈeppfϞ2?\lgJx7oV?RfefV :W:sg_~fF pl@2oקq$eW3'NOoR/uS?uRQhT_uV7u)oӀR,阰Be 0Ҳl4b|PCiᬡ1c?c~5Ӹ ) DHXh-hH/$vh>pY(԰1XD̀r)`TArAD(xos&mtmdw;mu'_m= Ird_ &POՎtozVQבVzzVuz级}ieC"3T ‚ o8 `e0gbZǠ 2۳8<+p l?cvRD"XfIHddL3hv82<]_KG(䙙tݫ;>`’(#H- Xy^~PU%Жp tH_yf]Y^rϕllpH֙+xOWoXIz~,h „ 2!Ĉ'Rh߆7r#Ȑ"G0e(XnXp@@ 3HDyw ,fĜQAuTyN<+P9i΍3X/s[=|<@n/??ynʃrqAXr.uQ ; H),H U^w,g0LAWJXQ, KP:)@t &3@-5Ei8hkl9Z' q< j4!r@sv @@84@r}XX%VG,mЀBFwXH4#DP"ĎSȰop xy JG $ HĀ<ѻu`aXXW t#`K^r?yѳVP巈'NRL ө1p zDr:V4 %/  &J>ꀒ1*7 Ph<3SL1 N"nNk1Y6 e{K6MSN|1_Eߨ./.~P`Ya< Cs"J8C򶷾-p+=.r;{)<4()'f K7d%`A;.0pS8v*["6R}|JD$P `ЩN@xPI RMPc#xЇbII w4@  hPWрB'~1_4Z0WCL@M!(B(@ N[t᳤-?F}wP=a:2BUS֚D,ò/)H>4E3ыf^!)Jtf$ =YBDHS{;BX:JF!0M PK#E㞨Ru uOSAHh Jhhd84RBA]#qІy @$ -a \P?\a-ЂL?VMB9(^F Vsx Z702Ama¼@?_ H^s'w D*6>2~:ԣ.S>14*%H J63SSRⳫH% XBILd SJ D\ɾuJa_-gY,f3HPH@s\)ưl ,o{&V<J Dvp̛ }GzB2%rlAp-)UҍqB0d '!8T@ Dg?O$ܩ? pD)}6_x_e1 TV^ RH \SIP JDlZCSԁQD ~Pl`)wI3jEU}T\̅}E)MH0@< tcH@ 8Cx,(? YK}hpFCC .l1@B4i,Bx99 UH_TYu_8*+<`6MHbx wt*wRmbwb1/r3C+f 5V5^#6@1 :@IXD8ݝcvAIBICJ,M|1m]~i,-@A <؀@,EA4T h|۔rQ?4?`:8Ё,,!8p"A& )Ll@ec(`II`а KHT4 Ϝ J\&T R jԜhMW ] GZ0,TMMJ<+At@4AHA<J$ 6A Émt$,hA!4% bA  8 @._&geEdAXX"3`bBcN脦Xeb(n]((4舾"(Y&ƨΨ6&&HH{TL B)>]&ZKT+0 2 hvC F}y@3h$@CL//C20 #0+܁`$ BA8a(7p?))A$N?x?" p3%yn&<%* L\ &2 't)ƃF尲"녞h&++h]J(VkZ+kv賎*(VhZ;`Q TEAELPET̝̀;(f6@Q@ L ?@)|!1H7L!|l#oD|A zk8--ܖemXmގhZk-.ߺm-8+V6ZbH\Sk4TST?#46 Ъ3@pVɟlCo q ݉q: ,-$$7@ j Xo<vt5$:3B&C@$9A.l.g?$ l6hg. 9j tR$ޕ@: 9@u0@]3:t:d@-M=xᚁv zqowޖo#o+;n?oOp;37udzv7w ޚ7$t3 yA? ssA9s7Cvs3<'1pi?4q}vx' hpiWv>Z h4xB7¤]ό×Q2iN4L|I1TS<@Sq\ :@@(hC51p.8(,M9C!HC`v@+ 4A,(ҧ*(Bh&r0N']X& LX%_Z~:a8D3]'@"\Eg@~dz3"Ԓ-\_-#60ӭ{4zߺ-7:Џ -z;zv7${ۺ  -%wﺶ~ہ:ixOHCTuBR\>@I;)4 ӜI#EQ&l$yW"|!4 #/(8t(D xy$$AYs%;(7p7¶8*@p,C'*C8?& _}.eh["ߕ8A Hsk_}'5׻?CC%%t AޚAz'L@9{v?> tY,@{4>}~ +Y8;} ݵ D@лLƃEJ?3x> 4@*A4pxPDf``tpB=A)AjiPҧA/I Ԓ㿘2%Ҋ8IPB 5*D7~*uj!J2́.B\Q@֥fBe= -eȒG#zYH`] 6#(/B i (liN >`^8Ԣƨ0QhB .pOe!^Ofb]a]r"2/2#&@) l3,nFH4 np l@D!xN an${\pGց@~ RaV a9G'j(m֡f>) ag!_ dbphebj.&`ggL\0"X6aiQo@9*4`3l4x@l)lo  `J:.*K=: 2pD! "aҡ(@(@D2%= h` J   j &a ɯd0aIƁ)t΁`T`EB5TzE` ~ adIp~.QFA```C:P.$`Q@3 XZ ~ 7c1X3uƕ X4)NQ TZSP^`GQEVx{XU^ dEkB`e; & XbNa^ #sgf"+jFhFf!@Eani%z)0:&[X8#%B &!ZƉZT!ِTg]6)\eCqƑ)̌朲@ @2Fo1 H`l!6|)8RF4lzo1I;ޠq rsJA7KRt+'(A``"Aa@MI$ @@1@NkΦ7*`N3R WoI- 73 @$J62<^:%  )o9!^l CϟA:Td2UEZ ~AĀ!Pd(pd%H D 耧zkTIv2aJj x`R.@ ڨXA,UF`a[,A ¡5ȿgxA.`\!]wZ\zn!:/WX\gT ] ݍ@#3C[]9 pN& * 8<4LWϚ:2ƒA A l@` Mܙu! Dax@ Π Hq`)a6؆@:F@gxAE!xSD2.Ɓ~rgWX\~C :>GȻ7$Pp8Q`T`Ul aˇX:/!OF`U FNlB!(!x x\ZZ^Ǟ{)@#ʪlo n8*4& ao*3@[QtrKy| >N I`>@ l@Pt$@OCMX֠ dހd( :AE}Wr|pd@0R$=`G~rWIH*VGU@~; AFbQBc'F%&@`?~6@qa<0ɨ(jT -:,8 5乴3_ > QDUlr q ]0bF~nZN)̭N6X- Ě=6ڵlۺ} 7ܹtm[C|%0 30bŁ0eɓX` X8pe,މi([}b)zwċ.ƟPε"*݉OӨk&Œʈ+ Ą[ $`)إ0Fɿg p(: HI.*`?8a60 ! an#B N0EA@d@@- C AEP|3dJ4^UT1-ՊGYR$.=4 EFNy5.L `GD _Dd.U[IQ(.AV-_NJi^iN`}a%v3@&T@`AAPqQ`!+DA`Y V@z8vg\ ' P%`"3| ,U $t7 6@+3 # |1IaLB$ R" %* 8.~83N&`,&xПB?7GDNQ͈CL19LSAE"ZCJΩuRя0!9@ irLD FG)imO%8>MDQb["I%L6^< |/JnJz馟z꪿5a 4Q`a XT &fHZ+l!u norm%hm,c7$` ,X;Mñ?ٵVK:ACݨDcN3Qȝ(DެjUnWmd(` @zlɢ8߻XZ<`bk8>@C$BwHP"2 i:!f z@\lb8 @12R`poFĊBCDS3"0bbeXh g"\h&T8RqIJ-&I$DTP4u*uE`qy婒U)ʖEE&PDIS E"6Ys[ٹIэ<5عh 2i@ o@/MhbbLEk(ꐑR?PK*Pn{4hժ(@WmL\ȘxifuY308-P1Y NLoo80x:aHBH :J8 $HC A\@P EEP[`*h!b&Q5Ђ@R:nK|B"a7'+zP Ţ`Z4|" C1AA]r WNH _cs<ocٿd =*BksH|*H;ծZD M@'i 00""r6# `}O  rb E`A2P&`V@ LRqLIDI NtAF52&` \jl ۰ݐP d@G` } yIf5y vU ehHXӉfgSpYȜy9z`؉kh`|`jfk  j``!hi@ 拥Xiu{ߐ`q{ihfxib|x* iYFJ epi*(i ijV{FJg fd` dOn eSl ll۠x `ǀ,[ q ,ωK +sy=-ơ }؉,[ KYȬǕ|<0LwKa *|9 ˠLf̳ŧݯ `ܥ7*ܐL|۝h x=\h붗FXLN+.Ͽ ˽hAKZް,9;0Ģ[ϛp$F)-tJ]uaF9]S 0@ *ii 0` 6`@\pd@b &PCb0|@jb0A\$p dZ6w0Þiggm Z;T| ` pmmؚms\ۘv,٤]M٦~ŕ흡>0ǡmع[̰^ Ky}?J|{ިYTuaj]܄Мej̐v΢lkIoY Nڶ̇ɭ ۿ}qN:orB_IƧQP(@L2LآL=I @  00 U/ g  @cA bmP ? °@NB+ /DEP ր^X`IDk=Plfm T<ޛn}0z;ٙ>|LǾiȚ>Ƕo.وl鮾ؠ~ǿo`xǥ kٵM ȡ k{hvg}y?e$ퟖ}߿FC$2琢 M|@rJC0C% p:J|q@ ƖWfK 5xqW /*L+c-23ى1/] /|P&e4voY2 FsP t=zAO֫Kf;vH Ҧ]󪴂e O*¤XՁ m*B0P 3H  BhşXh"O8!3I'2H`Ǔ@i1<! !cbfCUWXdE(F6qDHOQ?_&0te 0,l }L*sMt; 3/t=S6U w!1B]G v#SWy ]kI,0D=4}uSFtIdZ Q] y#'@rȮF*$&l^@ɉ O IH>*0OJH@5_-+~PeCQ]71.(TI2b9,aK?1f5aH#f6Y R >y1@A+c AYC$~`ky @؀=%d %`N | (=`ELʛ25Iܲ,Nr&ir9YtES;:GґLy K S8Miv4'}w<Lfҝ%&.z\dh+  ZF$P6ԡ%ЫhS%D1-nMF;T (E1RbAd,߈.QyHd'JF O4QfŒf5$X7`"D2ILB3AF4FH2p4R C%XN0GH`h D<B%mP ,`_ (@eQm;\M+rUi> E1]e1C61>5Or*iywSp\s3IsBr+ms<6ٍ.7sՓ\R51T]0o|;_׾o~Yr+ꗦ@=M:X`N5 CNC;X1XS[ԓA5e+7 Q8 B$HGM*9 *U #Rp4CN؀X@J0@ 2VirE8]?,gLjsjn-d9lcGow$/p N=r\[G 49|JwU? ABCDEFGHIVServer]Accept-RangesZConnection\Content-TypeTDate]Last-Modified^Content-LengthTEtagZKeep-AliveVApacheUbytesZKeep-AliveYimage/gif_Tue, 11 Oct 2011 17:18:04 GMT_Thu, 25 Aug 2011 09:23:45 GMTU31699_W/"31699-1314264225000"_timeout=15, max=99*+]^_NSMutableDictionary]_/\NSDictionary{*+bc_NSHTTPURLResponsede/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiverhi_WebResourceResponse#-27X^y|CHS\bekt}"'29?JTt)7ILbjd_ahttps://www.imperialcollegeunion.org/data/images/originals/chitter-chatter-banner-726x93-4098.gifcdefO#/** * SWFObject v1.5.1: Flash Player detection and embed - http://blog.deconcept.com/swfobject/ * * SWFObject is (c) 2007 Geoff Stearns and is released under the MIT License: * http://www.opensource.org/licenses/mit-license.php * */ if(typeof deconcept == "undefined") var deconcept = {}; if(typeof deconcept.util == "undefined") deconcept.util = {}; if(typeof deconcept.SWFObjectUtil == "undefined") deconcept.SWFObjectUtil = {}; deconcept.SWFObject = function(swf, id, w, h, ver, c, quality, xiRedirectUrl, redirectUrl, detectKey) { if (!document.getElementById) { return; } this.DETECT_KEY = detectKey ? detectKey : 'detectflash'; this.skipDetect = deconcept.util.getRequestParameter(this.DETECT_KEY); this.params = {}; this.variables = {}; this.attributes = []; if(swf) { this.setAttribute('swf', swf); } if(id) { this.setAttribute('id', id); } if(w) { this.setAttribute('width', w); } if(h) { this.setAttribute('height', h); } if(ver) { this.setAttribute('version', new deconcept.PlayerVersion(ver.toString().split("."))); } this.installedVer = deconcept.SWFObjectUtil.getPlayerVersion(); if (!window.opera && document.all && this.installedVer.major > 7) { // only add the onunload cleanup if the Flash Player version supports External Interface and we are in IE // fixes bug in some fp9 versions see http://blog.deconcept.com/2006/07/28/swfobject-143-released/ if (!deconcept.unloadSet) { deconcept.SWFObjectUtil.prepUnload = function() { __flash_unloadHandler = function(){}; __flash_savedUnloadHandler = function(){}; window.attachEvent("onunload", deconcept.SWFObjectUtil.cleanupSWFs); } window.attachEvent("onbeforeunload", deconcept.SWFObjectUtil.prepUnload); deconcept.unloadSet = true; } } if(c) { this.addParam('bgcolor', c); } var q = quality ? quality : 'high'; this.addParam('quality', q); this.setAttribute('useExpressInstall', false); this.setAttribute('doExpressInstall', false); var xir = (xiRedirectUrl) ? xiRedirectUrl : window.location; this.setAttribute('xiRedirectUrl', xir); this.setAttribute('redirectUrl', ''); if(redirectUrl) { this.setAttribute('redirectUrl', redirectUrl); } } deconcept.SWFObject.prototype = { useExpressInstall: function(path) { this.xiSWFPath = !path ? "expressinstall.swf" : path; this.setAttribute('useExpressInstall', true); }, setAttribute: function(name, value){ this.attributes[name] = value; }, getAttribute: function(name){ return this.attributes[name] || ""; }, addParam: function(name, value){ this.params[name] = value; }, getParams: function(){ return this.params; }, addVariable: function(name, value){ this.variables[name] = value; }, getVariable: function(name){ return this.variables[name] || ""; }, getVariables: function(){ return this.variables; }, getVariablePairs: function(){ var variablePairs = []; var key; var variables = this.getVariables(); for(key in variables){ variablePairs[variablePairs.length] = key +"="+ variables[key]; } return variablePairs; }, getSWFHTML: function() { var swfNode = ""; if (navigator.plugins && navigator.mimeTypes && navigator.mimeTypes.length) { // netscape plugin architecture if (this.getAttribute("doExpressInstall")) { this.addVariable("MMplayerType", "PlugIn"); this.setAttribute('swf', this.xiSWFPath); } swfNode = ' 0){ swfNode += 'flashvars="'+ pairs +'"'; } swfNode += '/>'; } else { // PC IE if (this.getAttribute("doExpressInstall")) { this.addVariable("MMplayerType", "ActiveX"); this.setAttribute('swf', this.xiSWFPath); } swfNode = ''; swfNode += ''; var params = this.getParams(); for(var key in params) { swfNode += ''; } var pairs = this.getVariablePairs().join("&"); if(pairs.length > 0) {swfNode += '';} swfNode += ""; } return swfNode; }, write: function(elementId){ if(this.getAttribute('useExpressInstall')) { // check to see if we need to do an express install var expressInstallReqVer = new deconcept.PlayerVersion([6,0,65]); if (this.installedVer.versionIsValid(expressInstallReqVer) && !this.installedVer.versionIsValid(this.getAttribute('version'))) { this.setAttribute('doExpressInstall', true); this.addVariable("MMredirectURL", escape(this.getAttribute('xiRedirectUrl'))); document.title = document.title.slice(0, 47) + " - Flash Player Installation"; this.addVariable("MMdoctitle", document.title); } } if(this.skipDetect || this.getAttribute('doExpressInstall') || this.installedVer.versionIsValid(this.getAttribute('version'))){ var n = (typeof elementId == 'string') ? document.getElementById(elementId) : elementId; n.innerHTML = this.getSWFHTML(); return true; }else{ if(this.getAttribute('redirectUrl') != "") { document.location.replace(this.getAttribute('redirectUrl')); } } return false; } } /* ---- detection functions ---- */ deconcept.SWFObjectUtil.getPlayerVersion = function(){ var PlayerVersion = new deconcept.PlayerVersion([0,0,0]); if(navigator.plugins && navigator.mimeTypes.length){ var x = navigator.plugins["Shockwave Flash"]; if(x && x.description) { PlayerVersion = new deconcept.PlayerVersion(x.description.replace(/([a-zA-Z]|\s)+/, "").replace(/(\s+r|\s+b[0-9]+)/, ".").split(".")); } }else if (navigator.userAgent && navigator.userAgent.indexOf("Windows CE") >= 0){ // if Windows CE var axo = 1; var counter = 3; while(axo) { try { counter++; axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+ counter); // document.write("player v: "+ counter); PlayerVersion = new deconcept.PlayerVersion([counter,0,0]); } catch (e) { axo = null; } } } else { // Win IE (non mobile) // do minor version lookup in IE, but avoid fp6 crashing issues // see http://blog.deconcept.com/2006/01/11/getvariable-setvariable-crash-internet-explorer-flash-6/ try{ var axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); }catch(e){ try { var axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); PlayerVersion = new deconcept.PlayerVersion([6,0,21]); axo.AllowScriptAccess = "always"; // error if player version < 6.0.47 (thanks to Michael Williams @ Adobe for this code) } catch(e) { if (PlayerVersion.major == 6) { return PlayerVersion; } } try { axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); } catch(e) {} } if (axo != null) { PlayerVersion = new deconcept.PlayerVersion(axo.GetVariable("$version").split(" ")[1].split(",")); } } return PlayerVersion; } deconcept.PlayerVersion = function(arrVersion){ this.major = arrVersion[0] != null ? parseInt(arrVersion[0]) : 0; this.minor = arrVersion[1] != null ? parseInt(arrVersion[1]) : 0; this.rev = arrVersion[2] != null ? parseInt(arrVersion[2]) : 0; } deconcept.PlayerVersion.prototype.versionIsValid = function(fv){ if(this.major < fv.major) return false; if(this.major > fv.major) return true; if(this.minor < fv.minor) return false; if(this.minor > fv.minor) return true; if(this.rev < fv.rev) return false; return true; } /* ---- get value of query string param ---- */ deconcept.util = { getRequestParameter: function(param) { var q = document.location.search || document.location.hash; if (param == null) { return q; } if(q) { var pairs = q.substring(1).split("&"); for (var i=0; i < pairs.length; i++) { if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) { return pairs[i].substring((pairs[i].indexOf("=")+1)); } } } return ""; } } /* fix for video streaming bug */ deconcept.SWFObjectUtil.cleanupSWFs = function() { var objects = document.getElementsByTagName("OBJECT"); for (var i = objects.length - 1; i >= 0; i--) { objects[i].style.display = 'none'; for (var x in objects[i]) { if (typeof objects[i][x] == 'function') { objects[i][x] = function(){}; } } } } /* add document.getElementById if needed (mobile IE < 5) */ if (!document.getElementById && document.all) { document.getElementById = function(id) { return document.all[id]; }} /* add some aliases for ease of use/backwards compatibility */ var getQueryParamValue = deconcept.util.getRequestParameter; var FlashObject = deconcept.SWFObject; // for legacy support var SWFObject = deconcept.SWFObject; _application/x-javascriptObplist00noX$versionX$objectsY$archiverT$top""()0!12NOPQRSTUVWXYZ[\]^_`abcdhiU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1 !#$%&[NS.relativeWNS.base_Jhttps://www.imperialcollegeunion.org/data/static/site/js/swfobject1-5-1.js*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#AD3456BWNS.keysZNS.objects789:;<=>?@A CDEFGHIJKLMVServer]Accept-RangesZConnection\Content-TypeTDate]Last-Modified^Content-Length_Content-EncodingTVaryTEtagZKeep-AliveVApacheUbytesZKeep-Alive_application/x-javascript_Tue, 11 Oct 2011 17:18:04 GMT_Fri, 30 Sep 2011 13:41:44 GMTT2961Tgzip_Accept-Encoding_"176800c-23f9-4ae28c92df600"_timeout=15, max=99*+ef_NSMutableDictionaryeg/\NSDictionary#*+jk_NSHTTPURLResponselm/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiverpq_WebResourceResponse#-27\b}05@IORXajls{ .38CJP[v !%25:NRftr_Jhttps://www.imperialcollegeunion.org/data/static/site/js/swfobject1-5-1.jshijkOC/* Copyright (c) 2009, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt version: 2.7.0 */ if(typeof YAHOO=="undefined"||!YAHOO){var YAHOO={}}YAHOO.namespace=function(){var a=arguments,b=null,c,d,e;for(c=0;c0)?p.dump(a[c],b-1):f)}else{e.push(a[c])}e.push(h)}if(e.length>1){e.pop()}e.push("]")}else{e.push("{");for(c in a){if(p.hasOwnProperty(a,c)){e.push(c+i);if(p.isObject(a[c])){e.push((b>0)?p.dump(a[c],b-1):f)}else{e.push(a[c])}e.push(h)}}if(e.length>1){e.pop()}e.push("}")}return e.join("")},substitute:function(a,b,c){var d,e,f,g,h,i,k=[],m,n="dump",j=" ",o="{",q="}",l;for(;;){d=a.lastIndexOf(o);if(d<0){break}e=a.indexOf(q,d);if(d+1>=e){break}m=a.substring(d+1,e);g=m;i=null;f=g.indexOf(j);if(f>-1){i=g.substring(f+1);g=g.substring(0,f)}h=b[g];if(c){h=c(g,h,i)}if(p.isObject(h)){if(p.isArray(h)){h=p.dump(h,parseInt(i,10))}else{i=i||"";l=i.indexOf(n);if(l>-1){i=i.substring(4)}if(h.toString===y.toString||l>-1){h=p.dump(h,parseInt(i,10))}else{h=h.toString()}}}else{if(!p.isString(h)&&!p.isNumber(h)){h="~-"+k.length+"-~";k[k.length]=m}}a=a.substring(0,d)+h+a.substring(e+1)}for(d=k.length-1;d>=0;d=d-1){a=a.replace(new RegExp("~-"+d+"-~"),"{"+k[d]+"}","g")}return a},trim:function(a){try{return a.replace(/^\s+|\s+$/g,"")}catch(H){return a}},merge:function(){var a={},b=arguments,c=b.length,d;for(d=0;d519)?true:false);while((h=h[S])){g[0]+=h[A];g[1]+=h[L];if(f){g=j.Dom._calcBorders(h,g)}}if(j.Dom._getStyle(a,bg)!==bt){h=a;while((h=h[J])&&h[O]){d=h[Z];e=h[W];if(bc&&(j.Dom._getStyle(h,"overflow")!=="visible")){g=j.Dom._calcBorders(h,g)}if(d||e){g[0]-=e;g[1]-=d}}g[0]+=b;g[1]+=c}else{if(bp){g[0]-=b;g[1]-=c}else{if(bk||bc){g[0]+=b;g[1]+=c}}}g[0]=Math.floor(g[0]);g[1]=Math.floor(g[1])}else{}return g}}}(),getX:function(b){var c=function(a){return j.Dom.getXY(a)[0]};return j.Dom.batch(b,c,j.Dom,true)},getY:function(b){var c=function(a){return j.Dom.getXY(a)[1]};return j.Dom.batch(b,c,j.Dom,true)},setXY:function(a,b,c){j.Dom.batch(a,j.Dom._setXY,{pos:b,noRetry:c})},_setXY:function(a,b){var c=j.Dom._getStyle(a,bg),d=j.Dom.setStyle,e=b.pos,f=b.noRetry,g=[parseInt(j.Dom.getComputedStyle(a,bi),10),parseInt(j.Dom.getComputedStyle(a,bj),10)],h,i;if(c=="static"){c=bh;d(a,bg,c)}h=j.Dom._getXY(a);if(!e||h===false){return false}if(isNaN(g[0])){g[0]=(c==bh)?0:a[A]}if(isNaN(g[1])){g[1]=(c==bh)?0:a[L]}if(e[0]!==null){d(a,bi,e[0]-h[0]+g[0]+"px")}if(e[1]!==null){d(a,bj,e[1]-h[1]+g[1]+"px")}if(!f){i=j.Dom._getXY(a);if((e[0]!==null&&i[0]!=e[0])||(e[1]!==null&&i[1]!=e[1])){j.Dom._setXY(a,{pos:e,noRetry:true})}}},setX:function(a,b){j.Dom.setXY(a,[b,null])},setY:function(a,b){j.Dom.setXY(a,[null,b])},getRegion:function(c){var d=function(a){var b=false;if(j.Dom._canPosition(a)){b=j.Region.getRegion(a)}else{}return b};return j.Dom.batch(c,d,j.Dom,true)},getClientWidth:function(){return j.Dom.getViewportWidth()},getClientHeight:function(){return j.Dom.getViewportHeight()},getElementsByClassName:function(a,b,c,d,e,f){a=o.trim(a);b=b||"*";c=(c)?j.Dom.get(c):null||r;if(!c){return[]}var g=[],h=c.getElementsByTagName(b),i=j.Dom.hasClass;for(var k=0,m=h.length;k-1}}else{}return c},addClass:function(a,b){return j.Dom.batch(a,j.Dom._addClass,b)},_addClass:function(a,b){var c=false,d;if(a&&b){d=j.Dom.getAttribute(a,N)||V;if(!j.Dom._hasClass(a,b)){j.Dom.setAttribute(a,N,l(d+R+b));c=true}}else{}return c},removeClass:function(a,b){return j.Dom.batch(a,j.Dom._removeClass,b)},_removeClass:function(a,b){var c=false,d,e,f;if(a&&b){d=j.Dom.getAttribute(a,N)||V;j.Dom.setAttribute(a,N,d.replace(j.Dom._getClassRegex(b),V));e=j.Dom.getAttribute(a,N);if(d!==e){j.Dom.setAttribute(a,N,l(e));c=true;if(j.Dom.getAttribute(a,N)===""){f=(a.hasAttribute&&a.hasAttribute(bf))?bf:N;a.removeAttribute(f)}}}else{}return c},replaceClass:function(a,b,c){return j.Dom.batch(a,j.Dom._replaceClass,{from:b,to:c})},_replaceClass:function(a,b){var c,d,e,f=false,g;if(a&&b){d=b.from;e=b.to;if(!e){f=false}else{if(!d){f=j.Dom._addClass(a,b.to)}else{if(d!==e){g=j.Dom.getAttribute(a,N)||V;c=(R+g.replace(j.Dom._getClassRegex(d),R+e)).split(j.Dom._getClassRegex(e));c.splice(1,0,R+e);j.Dom.setAttribute(a,N,l(c.join(V)));f=true}}}}else{}return f},generateId:function(c,d){d=d||"yui-gen";var e=function(a){if(a&&a.id){return a.id}var b=d+YAHOO.env._id_counter++;if(a){if(a[w].getElementById(b)){return j.Dom.generateId(a,b+d)}a.id=b}return b};return j.Dom.batch(c,e,j.Dom,true)||e.apply(j.Dom,arguments)},isAncestor:function(a,b){a=j.Dom.get(a);b=j.Dom.get(b);var c=false;if((a&&b)&&(a[v]&&b[v])){if(a.contains&&a!==b){c=a.contains(b)}else{if(a.compareDocumentPosition){c=!!(a.compareDocumentPosition(b)&16)}}}else{}return c},inDocument:function(a,b){return j.Dom._inDoc(j.Dom.get(a),b)},_inDoc:function(a,b){var c=false;if(a&&a[O]){b=b||a[w];c=j.Dom.isAncestor(b[I],a)}else{}return c},getElementsBy:function(a,b,c,d,e,f,g){b=b||"*";c=(c)?j.Dom.get(c):null||r;if(!c){return[]}var h=[],i=c.getElementsByTagName(b);for(var k=0,m=i.length;k=this.left&&a.right<=this.right&&a.top>=this.top&&a.bottom<=this.bottom)};YAHOO.util.Region.prototype.getArea=function(){return((this.bottom-this.top)*(this.right-this.left))};YAHOO.util.Region.prototype.intersect=function(a){var b=Math.max(this.top,a.top),c=Math.min(this.right,a.right),d=Math.min(this.bottom,a.bottom),e=Math.max(this.left,a.left);if(d>=b&&c>=e){return new YAHOO.util.Region(b,c,d,e)}else{return null}};YAHOO.util.Region.prototype.union=function(a){var b=Math.min(this.top,a.top),c=Math.max(this.right,a.right),d=Math.max(this.bottom,a.bottom),e=Math.min(this.left,a.left);return new YAHOO.util.Region(b,c,d,e)};YAHOO.util.Region.prototype.toString=function(){return("Region {"+"top: "+this.top+", right: "+this.right+", bottom: "+this.bottom+", left: "+this.left+", height: "+this.height+", width: "+this.width+"}")};YAHOO.util.Region.getRegion=function(a){var b=YAHOO.util.Dom.getXY(a),c=b[1],d=b[0]+a.offsetWidth,e=b[1]+a.offsetHeight,f=b[0];return new YAHOO.util.Region(c,d,e,f)};YAHOO.util.Point=function(a,b){if(YAHOO.lang.isArray(a)){b=a[1];a=a[0]}YAHOO.util.Point.superclass.constructor.call(this,b,a,b,a)};YAHOO.extend(YAHOO.util.Point,YAHOO.util.Region);(function(){var i=YAHOO.util,k="clientTop",m="clientLeft",n="parentNode",j="right",o="hasLayout",q="px",l="opacity",p="auto",t="borderLeftWidth",s="borderTopWidth",y="borderRightWidth",r="borderBottomWidth",u="visible",w="transparent",K="height",I="width",x="style",A="currentStyle",L=/^width|height$/,S=/^(\d[.\d]*)+(em|ex|px|gd|rem|vw|vh|vm|ch|mm|cm|in|pt|pc|deg|rad|ms|s|hz|khz|%){1}?/i,J={get:function(a,b){var c="",d=a[A][b];if(b===l){c=i.Dom.getStyle(a,l)}else{if(!d||(d.indexOf&&d.indexOf(q)>-1)){c=d}else{if(i.Dom.IE_COMPUTED[b]){c=i.Dom.IE_COMPUTED[b](a,b)}else{if(S.test(d)){c=i.Dom.IE.ComputedStyle.getPixel(a,b)}else{c=d}}}}return c},getOffset:function(a,b){var c=a[A][b],d=b.charAt(0).toUpperCase()+b.substr(1),e="offset"+d,f="pixel"+d,g="",h;if(c==p){h=a[e];if(h===undefined){g=0}g=h;if(L.test(b)){a[x][b]=h;if(a[e]>h){g=h-(a[e]-h)}a[x][b]=p}}else{if(!a[x][f]&&!a[x][b]){a[x][b]=c}g=a[x][f]}return g+q},getBorderWidth:function(a,b){var c=null;if(!a[A][o]){a[x].zoom=1}switch(b){case s:c=a[k];break;case r:c=a.offsetHeight-a.clientHeight-a[k];break;case t:c=a[m];break;case y:c=a.offsetWidth-a.clientWidth-a[m];break}return c+q},getPixel:function(a,b){var c=null,d=a[A][j],e=a[A][b];a[x][j]=e;c=a[x].pixelRight;a[x][j]=d;return c+q},getMargin:function(a,b){var c;if(a[A][b]==p){c=0+q}else{c=i.Dom.IE.ComputedStyle.getPixel(a,b)}return c},getVisibility:function(a,b){var c;while((c=a[A])&&c[b]=="inherit"){a=a[n]}return(c)?c[b]:u},getColor:function(a,b){return i.Dom.Color.toRGB(a[A][b])||w},getBorderColor:function(a,b){var c=a[A],d=c[b]||c.color;return i.Dom.Color.toRGB(i.Dom.Color.toHex(d))}},v={};v.top=v.right=v.bottom=v.left=v[I]=v[K]=J.getOffset;v.color=J.getColor;v[s]=v[y]=v[r]=v[t]=J.getBorderWidth;v.marginTop=v.marginRight=v.marginBottom=v.marginLeft=J.getMargin;v.visibility=J.getVisibility;v.borderColor=v.borderTopColor=v.borderRightColor=v.borderBottomColor=v.borderLeftColor=J.getBorderColor;i.Dom.IE_COMPUTED=v;i.Dom.IE_ComputedStyle=J})();(function(){var e="toString",f=parseInt,g=RegExp,h=YAHOO.util;h.Dom.Color={KEYWORDS:{black:"000",silver:"c0c0c0",gray:"808080",white:"fff",maroon:"800000",red:"f00",purple:"800080",fuchsia:"f0f",green:"008000",lime:"0f0",olive:"808000",yellow:"ff0",navy:"000080",blue:"00f",teal:"008080",aqua:"0ff"},re_RGB:/^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,re_hex:/^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i,re_hex3:/([0-9A-F])/gi,toRGB:function(a){if(!h.Dom.Color.re_RGB.test(a)){a=h.Dom.Color.toHex(a)}if(h.Dom.Color.re_hex.exec(a)){a="rgb("+[f(g.$1,16),f(g.$2,16),f(g.$3,16)].join(", ")+")"}return a},toHex:function(a){a=h.Dom.Color.KEYWORDS[a]||a;if(h.Dom.Color.re_RGB.exec(a)){var b=(g.$1.length===1)?"0"+g.$1:Number(g.$1),c=(g.$2.length===1)?"0"+g.$2:Number(g.$2),d=(g.$3.length===1)?"0"+g.$3:Number(g.$3);a=[b[e](16),c[e](16),d[e](16)].join("")}if(a.length<6){a=a.replace(h.Dom.Color.re_hex3,"$1$1")}if(a!=="transparent"&&a.indexOf("#")<0){a="#"+a}return a.toLowerCase()}}}());YAHOO.register("dom",YAHOO.util.Dom,{version:"2.7.0",build:"1799"});YAHOO.util.CustomEvent=function(a,b,c,d){this.type=a;this.scope=b||window;this.silent=c;this.signature=d||YAHOO.util.CustomEvent.LIST;this.subscribers=[];if(!this.silent){}var e="_YUICEOnSubscribe";if(a!==e){this.subscribeEvent=new YAHOO.util.CustomEvent(e,this,true)}this.lastError=null};YAHOO.util.CustomEvent.LIST=0;YAHOO.util.CustomEvent.FLAT=1;YAHOO.util.CustomEvent.prototype={subscribe:function(a,b,c){if(!a){throw new Error("Invalid callback for subscriber to '"+this.type+"'");}if(this.subscribeEvent){this.subscribeEvent.fire(a,b,c)}this.subscribers.push(new YAHOO.util.Subscriber(a,b,c))},unsubscribe:function(a,b){if(!a){return this.unsubscribeAll()}var c=false;for(var d=0,e=this.subscribers.length;d0){m=c[0]}try{d=i.fn.call(k,m,i.obj)}catch(F){this.lastError=F;if(h){throw F;}}}else{try{d=i.fn.call(k,this.type,c,i.obj)}catch(H){this.lastError=H;if(h){throw H;}}}if(false===d){if(!this.silent){}break}}}return(d!==false)},unsubscribeAll:function(){var a=this.subscribers.length,b;for(b=a-1;b>-1;b--){this._delete(b)}this.subscribers=[];return a},_delete:function(a){var b=this.subscribers[a];if(b){delete b.fn;delete b.obj}this.subscribers.splice(a,1)},toString:function(){return"CustomEvent: "+"'"+this.type+"', "+"context: "+this.scope}};YAHOO.util.Subscriber=function(a,b,c){this.fn=a;this.obj=YAHOO.lang.isUndefined(b)?null:b;this.overrideContext=c};YAHOO.util.Subscriber.prototype.getScope=function(a){if(this.overrideContext){if(this.overrideContext===true){return this.obj}else{return this.overrideContext}}return a};YAHOO.util.Subscriber.prototype.contains=function(a,b){if(b){return(this.fn==a&&this.obj==b)}else{return(this.fn==a)}};YAHOO.util.Subscriber.prototype.toString=function(){return"Subscriber { obj: "+this.obj+", overrideContext: "+(this.overrideContext||"no")+" }"};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var p=false;var t=[];var s=[];var y=[];var r=[];var u=0;var w=[];var K=[];var I=0;var x={63232:38,63233:40,63234:37,63235:39,63276:33,63277:34,25:9};var A=YAHOO.env.ua.ie?"focusin":"focus";var L=YAHOO.env.ua.ie?"focusout":"blur";return{POLL_RETRYS:2000,POLL_INTERVAL:20,EL:0,TYPE:1,FN:2,WFN:3,UNLOAD_OBJ:3,ADJ_SCOPE:4,OBJ:5,OVERRIDE:6,lastError:null,isSafari:YAHOO.env.ua.webkit,webkit:YAHOO.env.ua.webkit,isIE:YAHOO.env.ua.ie,_interval:null,_dri:null,DOMReady:false,throwErrors:false,startInterval:function(){if(!this._interval){var a=this;var b=function(){a._tryPreloadAttach()};this._interval=setInterval(b,this.POLL_INTERVAL)}},onAvailable:function(a,b,c,d,e){var f=(YAHOO.lang.isString(a))?[a]:a;for(var g=0;g-1;d--){g=(this.removeListener(a[d],b,c)&&g)}return g}}if(!c||!c.call){return this.purgeElement(a,false,b)}if("unload"==b){for(d=s.length-1;d>-1;d--){f=s[d];if(f&&f[0]==a&&f[1]==b&&f[2]==c){s.splice(d,1);return true}}return false}var h=null;var i=arguments[3];if("undefined"===typeof i){i=this._getCacheIndex(a,b,c)}if(i>=0){h=t[i]}if(!a||!h){return false}if(this.useLegacyEvent(a,b)){var k=this.getLegacyIndex(a,b);var m=r[k];if(m){for(d=0,e=m.length;d0&&w.length>0)}var e=[];var f=function(a,b){var c=a;if(b.overrideContext){if(b.overrideContext===true){c=b.obj}else{c=b.overrideContext}}b.fn.call(c,b.obj)};var g,h,i,k,m=[];for(g=0,h=w.length;g-1;g--){i=w[g];if(!i||!i.id){w.splice(g,1)}}this.startInterval()}else{if(this._interval){clearInterval(this._interval);this._interval=null}}this.locked=false},purgeElement:function(a,b,c){var d=(YAHOO.lang.isString(a))?this.getEl(a):a;var e=this.getListeners(d,c),f,g;if(e){for(f=e.length-1;f>-1;f--){var h=e[f];this.removeListener(d,h.type,h.fn)}}if(b&&d&&d.childNodes){for(f=0,g=d.childNodes.length;f-1;d--){e=t[d];if(e){b.removeListener(e[b.EL],e[b.TYPE],e[b.FN],d)}}e=null}y=null;b._simpleRemove(window,"unload",b._unload)},_getScrollLeft:function(){return this._getScroll()[1]},_getScrollTop:function(){return this._getScroll()[0]},_getScroll:function(){var a=document.documentElement,b=document.body;if(a&&(a.scrollTop||a.scrollLeft)){return[a.scrollTop,a.scrollLeft]}else{if(b){return[b.scrollTop,b.scrollLeft]}else{return[0,0]}}},regCE:function(){},_simpleAdd:function(){if(window.addEventListener){return function(a,b,c,d){a.addEventListener(b,c,(d))}}else{if(window.attachEvent){return function(a,b,c,d){a.attachEvent("on"+b,c)}}else{return function(){}}}}(),_simpleRemove:function(){if(window.removeEventListener){return function(a,b,c,d){a.removeEventListener(b,c,(d))}}else{if(window.detachEvent){return function(a,b,c){a.detachEvent("on"+b,c)}}else{return function(){}}}}()}}();(function(){var b=YAHOO.util.Event;b.on=b.addListener;b.onFocus=b.addFocusListener;b.onBlur=b.addBlurListener;if(b.isIE){YAHOO.util.Event.onDOMReady(YAHOO.util.Event._tryPreloadAttach,YAHOO.util.Event,true);var c=document.createElement("p");b._dri=setInterval(function(){try{c.doScroll("left");clearInterval(b._dri);b._dri=null;b._ready();c=null}catch(ex){}},b.POLL_INTERVAL)}else{if(b.webkit&&b.webkit<525){b._dri=setInterval(function(){var a=document.readyState;if("loaded"==a||"complete"==a){clearInterval(b._dri);b._dri=null;b._ready()}},b.POLL_INTERVAL)}else{b._simpleAdd(document,"DOMContentLoaded",b._ready)}}b._simpleAdd(window,"load",b._load);b._simpleAdd(window,"unload",b._unload);b._tryPreloadAttach()})()}YAHOO.util.EventProvider=function(){};YAHOO.util.EventProvider.prototype={__yui_events:null,__yui_subscribers:null,subscribe:function(a,b,c,d){this.__yui_events=this.__yui_events||{};var e=this.__yui_events[a];if(e){e.subscribe(b,c,d)}else{this.__yui_subscribers=this.__yui_subscribers||{};var f=this.__yui_subscribers;if(!f[a]){f[a]=[]}f[a].push({fn:b,obj:c,overrideContext:d})}},unsubscribe:function(a,b,c){this.__yui_events=this.__yui_events||{};var d=this.__yui_events;if(a){var e=d[a];if(e){return e.unsubscribe(b,c)}}else{var f=true;for(var g in d){if(YAHOO.lang.hasOwnProperty(d,g)){f=f&&d[g].unsubscribe(b,c)}}return f}return false},unsubscribeAll:function(a){return this.unsubscribe(a)},createEvent:function(a,b){this.__yui_events=this.__yui_events||{};var c=b||{};var d=this.__yui_events;if(d[a]){}else{var e=c.scope||this;var f=(c.silent);var g=new YAHOO.util.CustomEvent(a,e,f,YAHOO.util.CustomEvent.FLAT);d[a]=g;if(c.onSubscribeCallback){g.subscribeEvent.subscribe(c.onSubscribeCallback)}this.__yui_subscribers=this.__yui_subscribers||{};var h=this.__yui_subscribers[a];if(h){for(var i=0;i-1},"|=":function(a,b){return a===b||a.slice(0,b.length+1)===b+"-"},"^=":function(a,b){return a.indexOf(b)===0},"$=":function(a,b){return a.slice(-b.length)===b},"*=":function(a,b){return a.indexOf(b)>-1},"":function(a,b){return a}},pseudos:{"root":function(a){return a===a.ownerDocument.documentElement},"nth-child":function(a,b){return l.Selector._getNth(a,b)},"nth-last-child":function(a,b){return l.Selector._getNth(a,b,null,true)},"nth-of-type":function(a,b){return l.Selector._getNth(a,b,a.tagName)},"nth-last-of-type":function(a,b){return l.Selector._getNth(a,b,a.tagName,true)},"first-child":function(a){return l.Selector._getChildren(a.parentNode)[0]===a},"last-child":function(a){var b=l.Selector._getChildren(a.parentNode);return b[b.length-1]===a},"first-of-type":function(a,b){return l.Selector._getChildren(a.parentNode,a.tagName)[0]},"last-of-type":function(a,b){var c=l.Selector._getChildren(a.parentNode,a.tagName);return c[c.length-1]},"only-child":function(a){var b=l.Selector._getChildren(a.parentNode);return b.length===1&&b[0]===a},"only-of-type":function(a){return l.Selector._getChildren(a.parentNode,a.tagName).length===1},"empty":function(a){return a.childNodes.length===0},"not":function(a,b){return!l.Selector.test(a,b)},"contains":function(a,b){var c=a.innerText||a.textContent||"";return c.indexOf(b)>-1},"checked":function(a){return a.checked===true}},test:function(a,b){a=l.Selector.document.getElementById(a)||a;if(!a){return false}var c=b?b.split(","):[];if(c.length){for(var d=0,e=c.length;d1){var h;for(var i=0,k=g.length;i"){b=f}}}}else{return e}}if(b&&!j.length){j=b.getElementsByTagName(q.tag)}if(j.length){e=l.Selector._filter(j,q,c,d)}return e},_clearFoundCache:function(){var a=l.Selector._foundCache;for(var b=0,c=a.length;b":function(a,b){return l.Selector._test(a.parentNode,null,b.previous)},"+":function(a,b){var c=a.previousSibling;while(c&&c.nodeType!==1){c=c.previousSibling}if(c&&l.Selector._test(c,null,b.previous)){return true}return false},"~":function(a,b){var c=a.previousSibling;while(c){if(c.nodeType===1&&l.Selector._test(c,null,b.previous)){return true}c=c.previousSibling}return false}},_getNth:function(a,b,c,d){l.Selector._re.nth.test(b);var e=parseInt(RegExp.$1,10),f=RegExp.$2,g=RegExp.$3,h=parseInt(RegExp.$4,10)||0,i=[],k;var m=l.Selector._getChildren(a.parentNode,c);if(g){e=2;k="+";f="n";h=(g==="odd")?1:0}else{if(isNaN(e)){e=(f)?1:0}}if(e===0){if(d){h=m.length-h+1}if(m[h-1]===a){return true}else{return false}}else{if(e<0){d=!!d;e=Math.abs(e)}}if(!d){for(var n=h-1,j=m.length;n=0&&m[n]===a){return true}}}else{for(var n=m.length-h,j=m.length;n>=0;n-=e){if(n+~]|\s)\s*/},_tokenize:function(a){var b={},c=[],d,e=false,f=l.Selector._patterns,g;a=l.Selector._replaceShorthand(a);do{e=false;for(var h in f){if(YAHOO.lang.hasOwnProperty(f,h)){if(h!="tag"&&h!="combinator"){b[h]=b[h]||[]}if((g=f[h].exec(a))){e=true;if(h!="tag"&&h!="combinator"){if(h==="attributes"&&g[1]==="id"){b.id=g[3]}b[h].push(g.slice(1))}else{b[h]=g[1]}a=a.replace(g[0],"");if(h==="combinator"||!a.length){b.attributes=l.Selector._fixAttributes(b.attributes);b.pseudos=b.pseudos||[];b.tag=b.tag?b.tag.toUpperCase():"*";c.push(b);b={previous:b}}}}}}while(e);return c},_fixAttributes:function(a){var b=l.Selector.attrAliases;a=a||[];for(var c=0,d=a.length;c0)?b:0}if("style"in d){o.Dom.setStyle(d,a,b+c)}else{if(a in d){d[a]=b}}},getAttribute:function(a){var b=this.getEl();var c=o.Dom.getStyle(b,a);if(c!=="auto"&&!this.patterns.offsetUnit.test(c)){return parseFloat(c)}var d=this.patterns.offsetAttribute.exec(a)||[];var e=!!(d[3]);var f=!!(d[2]);if("style"in b){if(f||(o.Dom.getStyle(b,"position")=="absolute"&&e)){c=b["offset"+d[0].charAt(0).toUpperCase()+d[0].substr(1)]}else{c=0}}else{if(a in b){c=b[a]}}return c},getDefaultUnit:function(a){if(this.patterns.defaultUnit.test(a)){return"px"}return""},setRuntimeAttribute:function(b){var c;var d;var e=this.attributes;this.runtimeAttributes[b]={};var f=function(a){return(typeof a!=="undefined")};if(!f(e[b]["to"])&&!f(e[b]["by"])){return false}c=(f(e[b]["from"]))?e[b]["from"]:this.getAttribute(b);if(f(e[b]["to"])){d=e[b]["to"]}else{if(f(e[b]["by"])){if(c.constructor==Array){d=[];for(var g=0,h=c.length;g0&&isFinite(f)){if(a.currentFrame+f>=b){f=b-(c+1)}a.currentFrame+=f}}};YAHOO.util.Bezier=new function(){this.getPosition=function(a,b){var c=a.length;var d=[];for(var e=0;e0&&!(e[0]instanceof Array)){e=[e]}else{var i=[];for(g=0,h=e.length;g0){this.runtimeAttributes[a]=this.runtimeAttributes[a].concat(e)}this.runtimeAttributes[a][this.runtimeAttributes[a].length]=f}else{j.setRuntimeAttribute.call(this,a)}};var q=function(a,b){var c=n.Dom.getXY(this.getEl());a=[a[0]-c[0]+b[0],a[1]-c[1]+b[1]];return a};var l=function(a){return(typeof a!=="undefined")};n.Motion=m})();(function(){var e=function(a,b,c,d){if(a){e.superclass.constructor.call(this,a,b,c,d)}};e.NAME="Scroll";var f=YAHOO.util;YAHOO.extend(e,f.ColorAnim);var g=e.superclass;var h=e.prototype;h.doMethod=function(a,b,c){var d=null;if(a=="scroll"){d=[this.method(this.currentFrame,b[0],c[0]-b[0],this.totalFrames),this.method(this.currentFrame,b[1],c[1]-b[1],this.totalFrames)]}else{d=g.doMethod.call(this,a,b,c)}return d};h.getAttribute=function(a){var b=null;var c=this.getEl();if(a=="scroll"){b=[c.scrollLeft,c.scrollTop]}else{b=g.getAttribute.call(this,a)}return b};h.setAttribute=function(a,b,c){var d=this.getEl();if(a=="scroll"){d.scrollLeft=b[0];d.scrollTop=b[1]}else{g.setAttribute.call(this,a,b,c)}};f.Scroll=e})();YAHOO.register("animation",YAHOO.util.Anim,{version:"2.7.0",build:"1799"});YAHOO.util.Connect={_msxml_progid:["Microsoft.XMLHTTP","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP"],_http_headers:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:"application/x-www-form-urlencoded; charset=UTF-8",_default_form_header:"application/x-www-form-urlencoded",_use_default_xhr_header:true,_default_xhr_header:"XMLHttpRequest",_has_default_headers:true,_default_headers:{},_isFormSubmit:false,_isFileUpload:false,_formNode:null,_sFormData:null,_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,_submitElementValue:null,_hasSubmitListener:(function(){if(YAHOO.util.Event){YAHOO.util.Event.addListener(document,"click",function(a){var b=YAHOO.util.Event.getTarget(a),c=b.nodeName.toLowerCase();if((c==="input"||c==="button")&&(b.type&&b.type.toLowerCase()=="submit")){YAHOO.util.Connect._submitElementValue=encodeURIComponent(b.name)+"="+encodeURIComponent(b.value)}});return true}return false})(),startEvent:new YAHOO.util.CustomEvent("start"),completeEvent:new YAHOO.util.CustomEvent("complete"),successEvent:new YAHOO.util.CustomEvent("success"),failureEvent:new YAHOO.util.CustomEvent("failure"),uploadEvent:new YAHOO.util.CustomEvent("upload"),abortEvent:new YAHOO.util.CustomEvent("abort"),_customEvents:{onStart:["startEvent","start"],onComplete:["completeEvent","complete"],onSuccess:["successEvent","success"],onFailure:["failureEvent","failure"],onUpload:["uploadEvent","upload"],onAbort:["abortEvent","abort"]},setProgId:function(a){this._msxml_progid.unshift(a)},setDefaultPostHeader:function(a){if(typeof a=="string"){this._default_post_header=a}else{if(typeof a=="boolean"){this._use_default_post_header=a}}},setDefaultXhrHeader:function(a){if(typeof a=="string"){this._default_xhr_header=a}else{this._use_default_xhr_header=a}},setPollingInterval:function(a){if(typeof a=="number"&&isFinite(a)){this._polling_interval=a}},createXhrObject:function(a){var b,c;try{c=new XMLHttpRequest();b={conn:c,tId:a}}catch(D){for(var d=0;d=200&&d<300||d===1223){e=this.createResponseObject(a,f);if(b&&b.success){if(!b.scope){b.success(e)}else{b.success.apply(b.scope,[e])}}this.successEvent.fire(e);if(a.successEvent){a.successEvent.fire(e)}}else{switch(d){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:e=this.createExceptionObject(a.tId,f,(c?c:false));if(b&&b.failure){if(!b.scope){b.failure(e)}else{b.failure.apply(b.scope,[e])}}break;default:e=this.createResponseObject(a,f);if(b&&b.failure){if(!b.scope){b.failure(e)}else{b.failure.apply(b.scope,[e])}}}this.failureEvent.fire(e);if(a.failureEvent){a.failureEvent.fire(e)}}this.releaseObject(a);e=null},createResponseObject:function(a,b){var c={};var d={};try{var e=a.conn.getAllResponseHeaders();var f=e.split("\n");for(var g=0;g-1){l=e.options[e.selectedIndex];k[m++]=f+encodeURIComponent((l.attributes.value&&l.attributes.value.specified)?l.value:l.text)}break;case"select-multiple":if(e.selectedIndex>-1){for(o=e.selectedIndex,q=e.options.length;o');if(typeof a=="boolean"){c.src="javascript:false"}}else{c=document.createElement("iframe");c.id=b;c.name=b}c.style.position="absolute";c.style.top="-1000px";c.style.left="-1000px";document.body.appendChild(c)},appendPostData:function(a){var b=[],c=a.split("&"),d,e;for(d=0;d0){for(m=0;m=420){h.addEventListener("load",function(){o(i,k)})}else{var q=p[i];if(q.varName){var l=YAHOO.util.Get.POLL_FREQ;q.maxattempts=YAHOO.util.Get.TIMEOUT/l;q.attempts=0;q._cache=q.varName[0].split(".");q.timer=u.later(l,q,function(a){var b=this._cache,c=b.length,d=this.win,e;for(e=0;ethis.maxattempts){var f="Over retry limit, giving up";q.timer.cancel();L(i,f)}else{}return}}q.timer.cancel();o(i,k)},null,true)}else{u.later(YAHOO.util.Get.POLL_FREQ,null,o,[i,k])}}}}else{h.onload=function(){o(i,k)}}}};return{POLL_FREQ:10,PURGE_THRESH:20,TIMEOUT:2000,_finalize:function(a){u.later(0,null,S,a)},abort:function(a){var b=(u.isString(a))?a:a.tId;var c=p[b];if(c){c.aborted=true}},script:function(a,b){return Z("script",a,b)},css:function(a,b){return Z("css",a,b)}}}();YAHOO.register("get",YAHOO.util.Get,{version:"2.7.0",build:"1799"});YAHOO.lang.JSON=(function(){var o=YAHOO.lang,q=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,l=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,t=/(?:^|:|,)(?:\s*\[)+/g,s=/^[\],:{}\s]*$/,y=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,r={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"};function u(f,g){var h=function(a,b){var c,d,e=a[b];if(e&&typeof e==="object"){for(c in e){if(o.hasOwnProperty(e,c)){d=h(e,c);if(d===undefined){delete e[c]}else{e[c]=d}}}}return g.call(a,b,e)};return typeof g==="function"?h({"":f},""):f}function w(a){if(!r[a]){r[a]="\\u"+("0000"+(+(a.charCodeAt(0))).toString(16)).slice(-4)}return r[a]}function K(a){return a.replace(q,w)}function I(a){return o.isString(a)&&s.test(a.replace(l,"@").replace(p,"]").replace(t,""))}function x(a){return'"'+a.replace(y,w)+'"'}function A(a,b,c,d,e){var f=typeof d==="function"?d.call(a,b,a[b]):a[b],g,h,i,k,m,n,j;if(f instanceof Date){f=o.JSON.dateToString(f)}else{if(f instanceof String||f instanceof Boolean||f instanceof Number){f=f.valueOf()}}switch(typeof f){case"string":return x(f);case"number":return isFinite(f)?String(f):"null";case"boolean":return String(f);case"object":if(f===null){return"null"}for(g=e.length-1;g>=0;--g){if(e[g]===f){return"null"}}e[e.length]=f;j=[];n=o.isArray(f);if(c>0){if(n){for(g=f.length-1;g>=0;--g){j[g]=A(f,g,c-1,d,e)||"null"}}else{i=0;if(o.isArray(d)){for(g=0,h=d.length;g=0?k:1/0;return A({"":h},"",k,i,[])}return undefined},dateToString:function(b){function c(a){return a<10?"0"+a:a}return b.getUTCFullYear()+"-"+c(b.getUTCMonth()+1)+"-"+c(b.getUTCDate())+"T"+c(b.getUTCHours())+":"+c(b.getUTCMinutes())+":"+c(b.getUTCSeconds())+"Z"},stringToDate:function(a){if(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z$/.test(a)){var b=new Date();b.setUTCFullYear(RegExp.$1,(RegExp.$2|0)-1,RegExp.$3);b.setUTCHours(RegExp.$4,RegExp.$5,RegExp.$6);return b}return a}}})();YAHOO.register("json",YAHOO.lang.JSON,{version:"2.7.0",build:"1799"});YAHOO.namespace("util");YAHOO.util.Cookie={_createCookieString:function(a,b,c,d){var e=YAHOO.lang;var f=encodeURIComponent(a)+"="+(c?encodeURIComponent(b):b);if(e.isObject(d)){if(d.expires instanceof Date){f+="; expires="+d.expires.toGMTString()}if(e.isString(d.path)&&d.path!=""){f+="; path="+d.path}if(e.isString(d.domain)&&d.domain!=""){f+="; domain="+d.domain}if(d.secure===true){f+="; secure"}}return f},_createCookieHashString:function(a){var b=YAHOO.lang;if(!b.isObject(a)){throw new TypeError("Cookie._createCookieHashString(): Argument must be an object.");}var c=new Array();for(var d in a){if(b.hasOwnProperty(a,d)&&!b.isFunction(a[d])&&!b.isUndefined(a[d])){c.push(encodeURIComponent(d)+"="+encodeURIComponent(String(a[d])))}}return c.join("&")},_parseCookieHash:function(a){var b=a.split("&"),c=null,d=new Object();if(a.length>0){for(var e=0,f=b.length;e0){var e=(c===false?function(a){return a}:decodeURIComponent);if(/[^=]+=[^=;]?(?:;[^=]+=[^=]?)?/.test(b)){var f=b.split(/;\s/g),g=null,h=null,i=null;for(var k=0,m=f.length;k=0?b.substr(a+1):null}function u(){var a,b,c=[],d=[];for(a in s){if(YAHOO.lang.hasOwnProperty(s,a)){b=s[a];c.push(a+"="+b.initialState);d.push(a+"="+b.currentState)}}p.value=c.join("&")+"|"+d.join("&");if(YAHOO.env.ua.webkit){p.value+="|"+y.join(",")}}function w(a){var b,c,d,e,f,g,h,i;if(!a){for(d in s){if(YAHOO.lang.hasOwnProperty(s,d)){e=s[d];e.currentState=e.initialState;e.onStateChange(unescape(e.currentState))}}return}f=[];g=a.split("&");for(b=0,c=g.length;b";try{c=l.contentWindow.document;c.open();c.write(b);c.close();return true}catch(M){return false}}function I(){var g,h,i,k;if(!l.contentWindow||!l.contentWindow.document){setTimeout(I,10);return}g=l.contentWindow.document;h=g.getElementById("state");i=h?h.innerText:null;k=r();setInterval(function(){var a,b,c,d,e,f;g=l.contentWindow.document;h=g.getElementById("state");a=h?h.innerText:null;e=r();if(a!==i){i=a;w(i);if(!i){b=[];for(c in s){if(YAHOO.lang.hasOwnProperty(s,c)){d=s[c];b.push(c+"="+d.initialState)}}e=b.join("&")}else{e=i}top.location.hash=e;k=e;u()}else{if(e!==k){k=e;K(e)}}},50);t=true;YAHOO.util.History.onLoadEvent.fire()}function x(){var d,e,f,g,h,i,k,m,n,j,o,q;f=p.value.split("|");if(f.length>1){k=f[0].split("&");for(d=0,e=k.length;d=2){h=g[0];j=g[1];i=s[h];if(i){i.currentState=j}}}}if(f.length>2){y=f[2].split(",")}if(YAHOO.env.ua.ie){if(typeof document.documentMode==="undefined"||document.documentMode<8){I()}else{YAHOO.util.Event.on(top,"hashchange",function(){var a=r();w(a);u()});t=true;YAHOO.util.History.onLoadEvent.fire()}}else{o=history.length;q=r();setInterval(function(){var a,b,c;b=r();c=history.length;if(b!==q){q=b;o=c;w(q);u()}else{if(c!==o&&YAHOO.env.ua.webkit){q=b;o=c;a=y[o-1];w(a);u()}}},50);t=true;YAHOO.util.History.onLoadEvent.fire()}}return{onLoadEvent:new YAHOO.util.CustomEvent("onLoad"),onReady:function(b,c,d){if(t){setTimeout(function(){var a=window;if(d){if(d===true){a=c}else{a=d}}b.call(a,"onLoad",[],c)},0)}else{YAHOO.util.History.onLoadEvent.subscribe(b,c,d)}},register:function(b,c,d,e,f){var g,h;if(typeof b!=="string"||YAHOO.lang.trim(b)===""||typeof c!=="string"||typeof d!=="function"){throw new Error("Missing or invalid argument");}if(s[b]){return}if(t){throw new Error("All modules must be registered before calling YAHOO.util.History.initialize");}b=escape(b);c=escape(c);g=null;if(f===true){g=e}else{g=f}h=function(a){return d.call(g,a,e)};s[b]={name:b,initialState:c,currentState:c,onStateChange:h}},initialize:function(a,b){if(t){return}if(YAHOO.env.ua.opera&&typeof history.navigationMode!=="undefined"){history.navigationMode="compatible"}if(typeof a==="string"){a=document.getElementById(a)}if(!a||a.tagName.toUpperCase()!=="TEXTAREA"&&(a.tagName.toUpperCase()!=="INPUT"||a.type!=="hidden"&&a.type!=="text")){throw new Error("Missing or invalid argument");}p=a;if(YAHOO.env.ua.ie&&(typeof document.documentMode==="undefined"||document.documentMode<8)){if(typeof b==="string"){b=document.getElementById(b)}if(!b||b.tagName.toUpperCase()!=="IFRAME"){throw new Error("Missing or invalid argument");}l=b}YAHOO.util.Event.onDOMReady(x)},navigate:function(a,b){var c;if(typeof a!=="string"||typeof b!=="string"){throw new Error("Missing or invalid argument");}c={};c[a]=b;return YAHOO.util.History.multiNavigate(c)},multiNavigate:function(a){var b,c,d,e,f;if(typeof a!=="object"){throw new Error("Missing or invalid argument");}if(!t){throw new Error("The Browser History Manager is not initialized");}for(c in a){if(!s[c]){throw new Error("The following module has not been registered: "+c);}}b=[];for(c in s){if(YAHOO.lang.hasOwnProperty(s,c)){d=s[c];if(YAHOO.lang.hasOwnProperty(a,c)){e=a[unescape(c)]}else{e=unescape(d.currentState)}c=escape(c);e=escape(e);b.push(c+"="+e)}}f=b.join("&");if(YAHOO.env.ua.ie&&(typeof document.documentMode==="undefined"||document.documentMode<8)){return K(f)}else{top.location.hash=f;if(YAHOO.env.ua.webkit){y[history.length]=f;u()}return true}},getCurrentState:function(a){var b;if(typeof a!=="string"){throw new Error("Missing or invalid argument");}if(!t){throw new Error("The Browser History Manager is not initialized");}b=s[a];if(!b){throw new Error("No such registered module: "+a);}return unescape(b.currentState)},getBookmarkedState:function(a){var b,c,d,e,f,g,h;if(typeof a!=="string"){throw new Error("Missing or invalid argument");}d=top.location.href.indexOf("#");if(d>=0){e=top.location.href.substr(d+1);f=e.split("&");for(b=0,c=f.length;b=0?b.substr(e+1):b;e=f.lastIndexOf("#");f=e>=0?f.substr(0,e):f;g=f.split("&");for(c=0,d=g.length;c=2){if(h[0]===a){return unescape(h[1])}}}return null}}})();YAHOO.register("history",YAHOO.util.History,{version:"2.7.0",build:"1799"});_application/x-javascriptO)bplist00z{X$versionX$objectsY$archiverT$top("()0!12TUVWXYZ[\]^_`abcdefghijklmnoptuU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1&'#$%&[NS.relativeWNS.base_,https://cdn.othermedia.com/ojay-yui/2.7.0.js*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#AD3456EWNS.keysZNS.objects%789:;<=>?@ABCD FGHIJKLMNOPQRS !"#$VServerZConnectionZKeep-Alive_Content-EncodingTVary\Content-TypeWExpires]Cache-Control]Accept-Ranges_X-Ua-Compatible]Last-ModifiedWX-CacheTDate^Content-LengthVApacheZKeep-Alive_timeout=2, max=100Tgzip_Accept-Encoding,U_application/x-javascript_Fri, 08 Oct 2021 17:18:04 GMT_max-age=315360000Ubytes]IE=EmulateIE7_Mon, 20 Apr 2009 15:43:50 GMT_MISS from cdn.othermedia.com_Tue, 11 Oct 2011 17:18:04 GMTU25404*+qr_NSMutableDictionaryqs/\NSDictionaryC*+vw_NSHTTPURLResponsexy/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiver|}_WebResourceResponse#-27bh(17:@IRT[cnp,>LTYhoz +Jjpu ~ _,https://cdn.othermedia.com/ojay-yui/2.7.0.jsmnopO/* Copyright (c) 2007-2008 James Coglan, http://jsclass.jcoglan.com Licensed under the MIT license, http://www.opensource.org/licenses/mit-license.php */ /** * JS.Class: Ruby-style JavaScript * Copyright (c) 2007-2009 James Coglan * * http://jsclass.jcoglan.com * http://github.com/jcoglan/js.class * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * Parts of this software are derived from the following open-source projects: * * - The Prototype framework, (c) 2005-2009 Sam Stephenson * - Alex Arnell's Inheritance library, (c) 2006, Alex Arnell * - Base, (c) 2006-9, Dean Edwards */ /** * == core == **/ /** section: core * JS * * The `JS` object is used as a namespace by the rest of the JS.Class framework, and hosts * various utility methods used throughout. None of these methods should be taken as being * public API, they are all 'plumbing' and may be removed or changed at any time. **/ JS = { /** * JS.extend(target, extensions) -> Object * - target (Object): object to be extended * - extensions (Object): object containing key/value pairs to add to target * * Adds the properties of the second argument to the first, and returns the first. Will not * needlessly overwrite fields with identical values; if an object has inherited a property * we should not add the property to the object itself. **/ extend: function(target, extensions) { extensions = extensions || {}; for (var prop in extensions) { if (target[prop] === extensions[prop]) continue; target[prop] = extensions[prop]; } return target; }, /** * JS.makeFunction() -> Function * * Returns a function for use as a constructor. These functions are used as the basis for * classes. The constructor calls the object's `initialize()` method if it exists. **/ makeFunction: function() { return function() { return this.initialize ? (this.initialize.apply(this, arguments) || this) : this; }; }, /** * JS.makeBridge(klass) -> Object * - klass (JS.Class): class from which you want to inherit * * Takes a class and returns an instance of it, without calling the class's constructor. * Used for forging prototype links between objects using JavaScript's inheritance model. **/ makeBridge: function(klass) { var bridge = function() {}; bridge.prototype = klass.prototype; return new bridge; }, /** * JS.bind(object, func) -> Function * - object (Object): object to bind the function to * - func (Function): function that the bound function should call * * Takes a function and an object, and returns a new function that calls the original * function with `this` set to refer to the `object`. Used to implement `JS.Kernel#method`, * amongst other things. **/ bind: function() { var args = JS.array(arguments), method = args.shift(), object = args.shift() || null; return function() { return method.apply(object, args.concat(JS.array(arguments))); }; }, /** * JS.callsSuper(func) -> Boolean * - func (Function): function to test for super() calls * * Takes a function and returns `true` iff the function makes a call to `callSuper()`. * Result is cached on the function itself since functions are immutable and decompiling * them is expensive. We use this to determine whether to wrap the function when it's * added to a class; wrapping impedes performance and should be avoided where possible. **/ callsSuper: function(func) { return func.SUPER === undefined ? func.SUPER = /\bcallSuper\b/.test(func.toString()) : func.SUPER; }, /** * JS.mask(func) -> Function * - func (Function): function to obfuscate * * Disguises a function so that we cannot tell if it uses `callSuper()`. Sometimes we don't * want such functions to be wrapped by the inheritance system. Modifies the function's * `toString()` method and returns the function. **/ mask: function(func) { var string = func.toString().replace(/callSuper/g, 'super'); func.toString = function() { return string }; return func; }, /** * JS.array(iterable) -> Array * - iterable (Object): object you want to cast to an array * * Takes any iterable object (something with a `length` property) and returns a native * JavaScript `Array` containing the same elements. **/ array: function(iterable) { if (!iterable) return []; if (iterable.toArray) return iterable.toArray(); var length = iterable.length, results = []; while (length--) results[length] = iterable[length]; return results; }, /** * JS.indexOf(haystack, needle) -> Number * - haystack (Array): array to search * - needle (Object): object to search for * * Returns the index of the `needle` in the `haystack`, which is typically an `Array` or an * array-like object. Returns -1 if no matching element is found. We need this as older * IE versions don't implement `Array#indexOf`. **/ indexOf: function(haystack, needle) { for (var i = 0, n = haystack.length; i < n; i++) { if (haystack[i] === needle) return i; } return -1; }, /** * JS.isFn(object) -> Boolean * - object (Object): object to test * * Returns `true` iff the argument is a `Function`. **/ isFn: function(object) { return object instanceof Function; }, /** * JS.isType(object, type) -> Boolean * - object (Object): object whose type we wish to check * - type (JS.Module): type to match against * * Returns `true` iff `object is of the given `type`. **/ isType: function(object, type) { if (!object || !type) return false; return (type instanceof Function && object instanceof type) || (typeof type === 'string' && typeof object === type) || (object.isA && object.isA(type)); }, /** * JS.ignore(key, object) -> Boolean * - key (String): name of field being added to an object * - object (Object): value of the given field * * Used to determine whether a key-value pair should be added to a class or module. Pairs * may be ignored if they have some special function, like `include` or `extend`. **/ ignore: function(key, object) { return /^(include|extend)$/.test(key) && typeof object === 'object'; } }; /** section: core * class JS.Module * includes JS.Kernel * * `Module` is the core class in JS.Class. A module is simply an object that stores methods, * and is responsible for handling method lookups, inheritance relationships and the like. * All of Ruby's inheritance semantics are handled using modules in JS.Class. * * The basic object/module/class model in Ruby is expressed in the diagram at * http://ruby-doc.org/core/classes/Class.html -- `Class` inherits from `Module`, which * inherits from `Object` (as do all custom classes). `Kernel` is a `Module` which is mixed * into `Object` to provide methods common to all objects. * * In JS.Class, there is no `Object` class, but we do have `Module`, `Class` and `Kernel`. * All top-level (parentless) classes include the `JS.Kernel` module, so all classes in effect * inherit from `Kernel`. All classes are instances of `JS.Class`, and all modules instances * of `JS.Module`. `Module` is a top-level class, from which `Class` inherits. * * The following diagram shows this relationship; vertical lines indicate parent/child * class relationships, horizontal lines indicate module inclusions. (`C`) means a class, * (`M`) a module. * * * ============== ============== =================== ============== * | M | Kernel |----->| C | Module | | C | ParentClass |<-----| M | Kernel | * ============== ============== =================== ============== * ^ ^ * | | * | | * ============= ================== * | C | Class | | C | ChildClass | * ============= ================== * * * All objects have a metamodule attached to them; this handles storage of singleton * methods as metaclasses do in Ruby. This is handled by mixing the object's class into * the object's metamodule. * * * class * ================= * | C | SomeClass |------------------------------------------------ * ================= | * | | * V | * ==================== ================================= | * | |<>----| M | > |<----- * ==================== ================================= * instance metamodule * * * Similarly, inheritance of class methods is handled by mixing the parent class's * metamodule into the child class's metamodule, like so: * * * =================== ============================ * | C | ParentClass |<>----| M | |------ * =================== ============================ | * ^ | * | | * | | * =================== =========================== | * | C | ChildClass |<>----| M | |<------ * =================== =========================== * * * The parent-child relationships are also implemented using module inclusion, with some * extra checks and optimisations. Also, bear in mind that although `Class` appears to be a * subclass of `Module`, this particular parent-child relationship is faked using manual * delegation; every class has a hidden module attached to it that handles all the method * storage and lookup responsibilities. **/ JS.Module = JS.makeFunction(); JS.extend(JS.Module.prototype, { END_WITHOUT_DOT: /([^\.])$/, /** * new JS.Module(name, methods, options) * - name (String): the name of the module, used for debugging * - methods (Object): list of methods for the class * - options (Object): configuration options * * The `name` argument is optional and may be omitted; `name` is not used to assign * the class to a variable, it is only uses as metadata. The `options` object is used * to specify the target object that the module is storing methods for. * * var Runnable = new JS.Module('Runnable', { * run: function(args) { * // ... * } * }); **/ initialize: function(name, methods, options) { this.__mod__ = this; // Mirror property found in Class. Think of this as toModule() this.__inc__ = []; // List of modules included in this module this.__fns__ = {}; // Object storing methods belonging to this module this.__dep__ = []; // List modules and classes that depend on this module this.__mct__ = {}; // Cache table for method call lookups if (typeof name === 'string') { this.__nom__ = this.displayName = name; } else { this.__nom__ = this.displayName = ''; options = methods; methods = name; } options = options || {}; // Object to resolve methods onto this.__res__ = options._resolve || null; if (methods) this.include(methods, false); }, /** * JS.Module#setName(name) -> undefined * - name (String): the name for the module * * Sets the `displayName` of the module to the given value. Should be the fully-qualified * name, including names of the containing modules. **/ setName: function(name) { this.__nom__ = this.displayName = name || ''; for (var key in this.__mod__.__fns__) this.__name__(key); if (name && this.__meta__) this.__meta__.setName(name + '.'); }, /** * JS.Module#__name__(name) -> undefined * - name (String): the name of the method to assign a `displayName` to * * Assigns the `displayName` property to the named method using Ruby conventions for naming * instance and singleton methods. If the named field points to another `Module`, the name * change is applied recursively. **/ __name__: function(name) { if (!this.__nom__) return; var object = this.__mod__.__fns__[name] || {}; name = this.__nom__.replace(this.END_WITHOUT_DOT, '$1#') + name; if (JS.isFn(object.setName)) return object.setName(name); if (JS.isFn(object)) object.displayName = name; }, /** * JS.Module#define(name, func[, resolve = true[, options = {}]]) -> undefined * - name (String): the name of the method * - func (Function): a function implementing the method * - resolve (Boolean): sets whether to refresh method tables afterward * - options (Object): execution options * * Adds an instance method to the module with the given `name`. The `options` parameter is * for internal use to make sure callbacks fire on the correct objects, e.g. a class * uses a hidden module to store its methods, but callbacks should fire on the class, * not the module. **/ define: function(name, func, resolve, options) { var notify = (options || {})._notify || this; this.__fns__[name] = func; this.__name__(name); if (JS.Module._notify && notify && JS.isFn(func)) JS.Module._notify(name, notify); if (resolve !== false) this.resolve(); }, /** * JS.Module#instanceMethod(name) -> Function * - name (String): the name of the method * * Returns the named instance method from the module as an unbound function. **/ instanceMethod: function(name) { var method = this.lookup(name).pop(); return JS.isFn(method) ? method : null; }, /** * JS.Module#instanceMethods([includeSuper = true[, results]]) -> Array * - includeSuper (Boolean): whether to include ancestor methods * - results (Array): list of found method names (internal use) * * Returns an array of all the method names from the module. Pass `false` to ignore methods * inherited from ancestors. **/ instanceMethods: function(includeSuper, results) { var self = this.__mod__, results = results || [], ancestors = self.ancestors(), n = ancestors.length, name; for (name in self.__fns__) { if (self.__fns__.hasOwnProperty(name) && JS.isFn(self.__fns__[name]) && JS.indexOf(results, name) === -1) results.push(name); } if (includeSuper === false) return results; while (n--) ancestors[n].instanceMethods(false, results); return results; }, /** * JS.Module#include(module[, resolve = true[, options = {}]]) -> undefined * - module (JS.Module): the module to mix in * - resolve (Boolean): sets whether to refresh method tables afterward * - options (Object): flags to control execution * * Mixes `module` into the receiver or, if `module` is plain old object (rather than a * `JS.Module`) adds methods directly into the receiver. The `options` and `resolve` arguments * are mostly for internal use; `options` specifies objects that callbacks should fire on, * and `resolve` tells the module whether to resolve methods onto its target after adding * the methods. **/ include: function(module, resolve, options) { resolve = (resolve !== false); if (!module) return resolve ? this.resolve() : this.uncache(); options = options || {}; if (module.__mod__) module = module.__mod__; var inc = module.include, ext = module.extend, includer = options._included || this, modules, method, i, n; if (module.__inc__ && module.__fns__) { // module is a Module instance: make links and fire callbacks this.__inc__.push(module); module.__dep__.push(this); if (options._extended) module.extended && module.extended(options._extended); else module.included && module.included(includer); } else { // module is a normal object: add methods directly to this module if (options._recall) { // Second call: add all the methods for (method in module) { if (JS.ignore(method, module[method])) continue; this.define(method, module[method], false, {_notify: includer || options._extended || this}); } } else { // First call: handle include and extend blocks // Handle inclusions if (typeof inc === 'object' || JS.isType(inc, JS.Module)) { modules = [].concat(inc); for (i = 0, n = modules.length; i < n; i++) includer.include(modules[i], resolve, options); } // Handle extensions if (typeof ext === 'object' || JS.isType(ext, JS.Module)) { modules = [].concat(ext); for (i = 0, n = modules.length; i < n; i++) includer.extend(modules[i], false); includer.extend(); } // Make a second call to include(). This allows mixins to modify the // include() method and affect the addition of methods to this module options._recall = true; return includer.include(module, resolve, options); } } resolve ? this.resolve() : this.uncache(); }, /** * JS.Module#includes(module) -> Boolean * - module (JS.Module): a module to check for inclusion * * Returns `true` iff the receiver includes (i.e. inherits from) the given `module`, or * if the receiver and given `module` are the same object. Recurses over the receiver's * inheritance tree, could get expensive. **/ includes: function(module) { var self = this.__mod__, i = self.__inc__.length; if (Object === module || self === module || self.__res__ === module.prototype) return true; while (i--) { if (self.__inc__[i].includes(module)) return true; } return false; }, /** * JS.Module#match(object) -> Boolean * - object (Object): object to type-check * * Returns `true` if the receiver is in the inheritance chain of `object`. **/ match: function(object) { return object.isA && object.isA(this); }, /** * JS.Module#ancestors([results]) -> Array * - results (Array): list of found ancestors (internal use) * * Returns an array of the module's ancestor modules/classes, with the most distant * first and the receiver last. This is the opposite order to that given by Ruby, but * this order makes it easier to eliminate duplicates and preserve Ruby's inheritance * semantics with respect to the diamond problem. The `results` parameter is for internal * use; we recurse over the tree passing the same array around rather than generating * lots of arrays and concatenating. **/ ancestors: function(results) { var self = this.__mod__, cachable = (results === undefined), klass = (self.__res__||{}).klass, result = (klass && self.__res__ === klass.prototype) ? klass : self, i, n; if (cachable && self.__anc__) return self.__anc__.slice(); results = results || []; // Recurse over inclusions first for (i = 0, n = self.__inc__.length; i < n; i++) self.__inc__[i].ancestors(results); // If this module is not already in the list, add it if (JS.indexOf(results, result) === -1) results.push(result); if (cachable) self.__anc__ = results.slice(); return results; }, /** * JS.Module#lookup(name) -> Array * - name (String): the name of the method to search for * * Returns an array of all the methods in the module's inheritance tree with the given * `name`. Methods are returned in the same order as the modules in `JS.Module#ancestors`, * so the last method in the list will be called first, the penultimate on the first * `callSuper()`, and so on back through the list. **/ lookup: function(name) { var self = this.__mod__, cache = self.__mct__; if (cache[name]) return cache[name].slice(); var ancestors = self.ancestors(), results = [], i, n, method; for (i = 0, n = ancestors.length; i < n; i++) { method = ancestors[i].__mod__.__fns__[name]; if (method) results.push(method); } cache[name] = results.slice(); return results; }, /** * JS.Module#make(name, func) -> Function * - name (String): the name of the method being produced * - func (Function): a function implementing the method * * Returns a version of the function ready to be added to a prototype object. Functions * that use `callSuper()` must be wrapped to support that behaviour, other functions can * be used raw. **/ make: function(name, func) { if (!JS.isFn(func) || !JS.callsSuper(func)) return func; var module = this; return function() { return module.chain(this, name, arguments); }; }, /** * JS.Module#chain(self, name, args) -> Object * - self (Object): the receiver of the call * - name (String): the name of the method being called * - args (Array): list of arguments to begin the call * * Performs calls to functions that use `callSuper()`. Ancestor methods are looked up * dynamically at call-time; this allows `callSuper()` to be late-bound as in Ruby at the * cost of a little performance. Arguments to the call are stored so they can be passed * up the call stack automatically without the developer needing to pass them by hand. **/ chain: JS.mask( function(self, name, args) { var callees = this.lookup(name), // List of method implementations stackIndex = callees.length - 1, // Current position in the call stack currentSuper = self.callSuper, // Current super method attached to the receiver params = JS.array(args), // Copy of argument list result; // Set up the callSuper() method self.callSuper = function() { // Overwrite arguments specified explicitly var i = arguments.length; while (i--) params[i] = arguments[i]; // Step up the stack, call and step back down stackIndex -= 1; var returnValue = callees[stackIndex].apply(self, params); stackIndex += 1; return returnValue; }; // Call the last method in the stack result = callees.pop().apply(self, params); // Remove or reassign callSuper() method currentSuper ? self.callSuper = currentSuper : delete self.callSuper; return result; } ), /** * JS.Module#resolve([target = this]) -> undefined * - target (Object): the object to reflect methods onto * * Copies methods from the module onto the `target` object, wrapping methods where * necessary. The target will typically be a native JavaScript prototype object used * to represent a class. Recurses over this module's ancestors to make sure all applicable * methods exist. **/ resolve: function(target) { var self = this.__mod__, target = target || self, resolved = target.__res__, i, n, key, made; // Resolve all dependent modules if the target is this module if (target === self) { self.uncache(false); i = self.__dep__.length; while (i--) self.__dep__[i].resolve(); } if (!resolved) return; // Recurse over this module's ancestors for (i = 0, n = self.__inc__.length; i < n; i++) self.__inc__[i].resolve(target); // Wrap and copy methods to the target for (key in self.__fns__) { made = target.make(key, self.__fns__[key]); if (resolved[key] !== made) resolved[key] = made; } }, /** * JS.Module#uncache([recursive = true]) -> undefined * - recursive (Boolean): whether to clear the cache of all dependent modules * * Clears the ancestor and method table cahces for the module. This is used to invalidate * caches when modules are modified, to avoid some of the bugs that exist in Ruby. **/ uncache: function(recursive) { var self = this.__mod__, i = self.__dep__.length; self.__anc__ = null; self.__mct__ = {}; if (recursive === false) return; while (i--) self.__dep__[i].uncache(); } }); /** section: core * class JS.Class < JS.Module * * `Class` is a subclass of `JS.Module`; classes not only store methods but also spawn * new objects. In addition, classes have an extra type of inheritance on top of mixins, * in that each class can have a single parent class from which it will inherit both * instance and singleton methods. * * Refer to `JS.Module` for details of how inheritance is implemented in JS.Class. Though * `Class` is supposed to appear to be a subclass of `Module`, this relationship is * implemented by letting each `Class` hold a reference to an anonymous `Module` and * using manual delegation where necessary. **/ JS.Class = JS.makeFunction(); JS.extend(JS.Class.prototype = JS.makeBridge(JS.Module), { /** * new JS.Class(name, parent, methods) * - name (String): the name of the class, used for debugging * - parent (JS.Class): the parent class to inherit from * - methods (Object): list of methods for the class * * The `name` and `parent` arguments are both optional and may be omitted. `name` * is not used to assign the class to a variable, it is only uses as metadata. * The default parent class is `Object`, and all classes include the JS.Kernel * module. **/ initialize: function(name, parent, methods) { if (typeof name === 'string') { this.__nom__ = this.displayName = name; } else { this.__nom__ = this.displayName = ''; methods = parent; parent = name; } var klass = JS.extend(JS.makeFunction(), this); klass.klass = klass.constructor = this.klass; if (!JS.isFn(parent)) { methods = parent; parent = Object; } // Set up parent-child relationship, then add methods. Setting up a parent // class in JavaScript wipes the existing prototype object. klass.inherit(parent); klass.include(methods, false); klass.resolve(); // Fire inherited() callback on ancestors do { parent.inherited && parent.inherited(klass); } while (parent = parent.superclass); return klass; }, /** * JS.Class#inherit(klass) -> undefined * - klass (JS.Class): the class to inherit from * * Sets up the parent-child relationship to the parent class. This is a destructive action * in that the existing prototype will be discarded; always call this before adding any * methods to the class. **/ inherit: function(klass) { this.superclass = klass; // Mix the parent's metamodule into this class's metamodule if (this.__eigen__ && klass.__eigen__) this.extend(klass.__eigen__(), true); this.subclasses = []; (klass.subclasses || []).push(this); // Bootstrap JavaScript's prototypal inheritance model var p = this.prototype = JS.makeBridge(klass); p.klass = p.constructor = this; // Set up a module to store methods and delegate calls to // -- Class does not really subclass Module, instead each // Class has a Module that it delegates to this.__mod__ = new JS.Module(this.__nom__, {}, {_resolve: this.prototype}); this.include(JS.Kernel, false); if (klass !== Object) this.include(klass.__mod__ || new JS.Module(klass.prototype, {_resolve: klass.prototype}), false); }, /** * JS.Class#include(module[, resolve = true[, options = {}]]) -> undefined * - module (JS.Module): the module to mix in * - resolve (Boolean): sets whether to refresh method tables afterward * - options (Object): flags to control execution * * Mixes a `module` into the class if it's a `JS.Module` instance, or adds instance * methods to the class itself if given a plain old object. Overrides `JS.Module#include` * to make sure callbacks fire on the class rather than its delegating module. **/ include: function(module, resolve, options) { if (!module) return; var mod = this.__mod__, options = options || {}; options._included = this; return mod.include(module, resolve, options); }, /** * JS.Class#define(name, func[, resolve = true[, options = {}]]) -> undefined * - name (String): the name of the method * - func (Function): a function to implement the method * - resolve (Boolean): sets whether to refresh method tables afterward * - options (Object): options for internal use * * Adds an instance method to the class with the given `name`. The `options` parameter is * for internal use to make sure callbacks fire on the correct objects, e.g. a class * uses a hidden module to store its methods, but callbacks should fire on the class, * not the module. **/ define: function(name, func, resolve, options) { var module = this.__mod__; options = options || {}; options._notify = this; module.define(name, func, resolve, options); } }); // This file bootstraps the framework by redefining Module and Class using their // own prototypes and mixing in methods from Kernel, making these classes appear // to be instances of themselves. JS.Module = new JS.Class('Module', JS.Module.prototype); JS.Class = new JS.Class('Class', JS.Module, JS.Class.prototype); JS.Module.klass = JS.Module.constructor = JS.Class.klass = JS.Class.constructor = JS.Class; JS.extend(JS.Module, { _observers: [], methodAdded: function(block, context) { this._observers.push([block, context]); }, _notify: function(name, object) { var obs = this._observers, i = obs.length; while (i--) obs[i][0].call(obs[i][1] || null, name, object); } }); /** section: core * mixin JS.Kernel * * `Kernel` is the base module; all classes include the `Kernel`, so its methods become * available to all objects instantiated by JS.Class. As in Ruby, the core `Object` * methods are implemented here rather than in the base `Object` class. JS.Class does * not in fact have an `Object` class and does not modify the builtin JavaScript `Object` * class either. **/ JS.Kernel = JS.extend(new JS.Module('Kernel', { /** * JS.Kernel#__eigen__() -> JS.Module * * Returns the object's metamodule, analogous to calling `(class << self; self; end)` * in Ruby. Ruby's metaclasses are `Class`es, not just `Module`s, but so far I've not found * a compelling reason to enforce this. You cannot instantiate or subclass metaclasses * in Ruby, they only really exist to store methods so a module will suffice. **/ __eigen__: function() { if (this.__meta__) return this.__meta__; var me = this.__nom__, klass = this.klass.__nom__, name = me || (klass ? '#<' + klass + '>' : ''), module = this.__meta__ = new JS.Module(name ? name + '.' : '', {}, {_resolve: this}); module.include(this.klass.__mod__, false); return module; }, /** * JS.Kernel#equals(object) -> Boolean * - object (Object): object to compare to the receiver * * Returns `true` iff `object` is the same object as the receiver. Override to provide a * more meaningful comparison for use in sets, hashtables etc. **/ equals: function(object) { return this === object; }, /** * JS.Kernel#extend(module[, resolve = true]) -> undefined * - module (JS.Module): module with which to extend the object * - resolve (Boolean): whether to refresh method tables afterward * * Extends the object using the methods from `module`. If `module` is an instance of * `JS.Module`, it becomes part of the object's inheritance chain and any methods added * directly to the object will take precedence. Pass `false` as a second argument * to prevent the method resolution process from firing. **/ extend: function(module, resolve) { return this.__eigen__().include(module, resolve, {_extended: this}); }, /** * JS.Kernel#hash() -> String * * Returns a hexadecimal hashcode for the object for use in hashtables. By default, * this is a random number guaranteed to be unique to the object. If you override * this method, make sure that `a.equals(b)` implies `a.hash() === b.hash()`. **/ hash: function() { return this.__hashcode__ = this.__hashcode__ || JS.Kernel.getHashCode(); }, /** * JS.Kernel#isA(type) -> Boolean * - type (JS.Module): module or class to check the object's type against * * Returns `true` iff the object is an instance of `type` or one of its * subclasses, or if the object's class includes the module `type`. **/ isA: function(moduleOrClass) { return this.__eigen__().includes(moduleOrClass); }, /** * JS.Kernel#method(name) -> Function * - name (String): the name of the required method * * Returns the named method from the object as a bound function. **/ method: function(name) { var self = this, cache = self.__mcache__ = self.__mcache__ || {}; if ((cache[name] || {}).fn === self[name]) return cache[name].bd; return (cache[name] = {fn: self[name], bd: JS.bind(self[name], self)}).bd; }, /** * JS.Kernel#methods() -> Array * * Returns a list of all the method names defined on the object. **/ methods: function() { return this.__eigen__().instanceMethods(true); }, /** * JS.Kernel#tap(block[, context]) -> this * - block (Function): block of code to execute * - context (Object): sets the binding of `this` within `block` * * Executes the given function passing the object as a parameter, and returns the * object rather than the result of the function. Designed to 'tap into' a method * chain to inspect intermediate values. From the Ruby docs: * * list .tap(function(x) { console.log("original: ", x) }) * .toArray() .tap(function(x) { console.log("array: ", x) }) * .select(condition) .tap(function(x) { console.log("evens: ", x) }) * .map(square) .tap(function(x) { console.log("squares: ", x) }) **/ tap: function(block, context) { block.call(context || null, this); return this; } }), { __hashIndex__: 0, getHashCode: function() { this.__hashIndex__ += 1; return (Math.floor(new Date().getTime() / 1000) + this.__hashIndex__).toString(16); } }); JS.Module.include(JS.Kernel); JS.extend(JS.Module, JS.Kernel.__fns__); JS.Class.include(JS.Kernel); JS.extend(JS.Class, JS.Kernel.__fns__); /** section: core * class JS.Interface * * `Interface` is a class used to encapsulate sets of methods and check whether objects * implement them. Think of interfaces as a means of duck-typing rather than as they are * used in Java. **/ JS.Interface = new JS.Class({ /** * new JS.Interface(methods) * - methods (Array): a list of method names * * An `Interface` is instantiated using a list of method names; these methods are the * API the interface can be used to check for. * * var HistoryInterface = new JS.Interface([ * 'getInitialState', * 'changeState' * ]); **/ initialize: function(methods) { this.test = function(object, returnName) { var n = methods.length; while (n--) { if (!JS.isFn(object[methods[n]])) return returnName ? methods[n] : false; } return true; }; }, /** * JS.Interface#test(object[, returnName = false]) -> Boolean | String * - object (Object): object whose API we wish to check * - returnName (Boolean): if true, return the first name found to be missing * * Checks whether `object` implements the interface, returning `true` or `false`. If * the second argument is `true`, returns the name of the first method found to be * missing from the object's API. **/ extend: { /** * JS.Interface.ensure(object, iface1[, iface2]) -> undefined * - object (Object): object whose API we wish to check * - iface (JS.Interface): interface the object should implement * * Throws an `Error` unless `object` implements the required interface(s). **/ ensure: function() { var args = JS.array(arguments), object = args.shift(), face, result; while (face = args.shift()) { result = face.test(object, true); if (result !== true) throw new Error('object does not implement ' + result + '()'); } } } }); /** section: core * class JS.Singleton * * `Singleton` is a class used to construct custom objects with all the inheritance features * of `JS.Class`, the methods from `JS.Kernel`, etc. It constructs an anonymous class from the * objects you provide and returns an instance of this class. **/ JS.Singleton = new JS.Class({ /** * new JS.Singleton(name, parent, methods) * - name (String): the name of the singleton, used for debugging * - parent (JS.Class): the parent class to inherit from * - methods (Object): list of methods for the singleton * * `Singleton`s are instantiated the same way as instances of `JS.Class`, the only difference * being that `Singleton` returns an instance of the newly created class, rather than the * class itself. **/ initialize: function(name, parent, methods) { return new (new JS.Class(name, parent, methods)); } }); JS.MethodChain = function(base) { var queue = [], baseObject = base || {}; this.____ = function(method, args) { queue.push({func: method, args: args}); }; this.fire = function(base) { return JS.MethodChain.fire(queue, base || baseObject); }; }; JS.MethodChain.fire = function(queue, object) { var method, property, i, n; loop: for (i = 0, n = queue.length; i < n; i++) { method = queue[i]; if (object instanceof JS.MethodChain) { object.____(method.func, method.args); continue; } switch (typeof method.func) { case 'string': property = object[method.func]; break; case 'function': property = method.func; break; case 'object': object = method.func; continue loop; break; } object = (typeof property === 'function') ? property.apply(object, method.args) : property; } return object; }; JS.MethodChain.prototype = { _: function() { var base = arguments[0], args, i, n; switch (typeof base) { case 'object': case 'function': args = []; for (i = 1, n = arguments.length; i < n; i++) args.push(arguments[i]); this.____(base, args); } return this; }, toFunction: function() { var chain = this; return function(object) { return chain.fire(object); }; } }; JS.MethodChain.reserved = (function() { var names = [], key; for (key in new JS.MethodChain) names.push(key); return new RegExp('^(?:' + names.join('|') + ')$'); })(); JS.MethodChain.addMethod = function(name) { if (this.reserved.test(name)) return; var func = this.prototype[name] = function() { this.____(name, arguments); return this; }; func.displayName = 'MethodChain#' + name; }; JS.MethodChain.displayName = 'MethodChain'; JS.MethodChain.addMethods = function(object) { var methods = [], property, i; for (property in object) Number(property) !== property && methods.push(property); if (object instanceof Array) { i = object.length; while (i--) typeof object[i] === 'string' && methods.push(object[i]); } i = methods.length; while (i--) this.addMethod(methods[i]); object.prototype && this.addMethods(object.prototype); }; it = its = function() { return new JS.MethodChain; }; JS.Module.methodAdded(function(name) { JS.MethodChain.addMethod(name); }); JS.Kernel.include({ wait: function(time) { var chain = new JS.MethodChain; typeof time === 'number' && setTimeout(chain.fire.bind(chain, this), time * 1000); this.forEach && typeof time === 'function' && this.forEach(function() { setTimeout(chain.fire.bind(chain, arguments[0]), time.apply(this, arguments) * 1000); }); return chain; }, _: function() { var base = arguments[0], args = [], i, n; for (i = 1, n = arguments.length; i < n; i++) args.push(arguments[i]); return (typeof base === 'object' && base) || (typeof base === 'function' && base.apply(this, args)) || this; } }, true); JS.Observable = new JS.Module('Observable', { extend: { DEFAULT_METHOD: 'update' }, addObserver: function(observer, context) { (this.__observers__ = this.__observers__ || []).push({_block: observer, _context: context || null}); }, removeObserver: function(observer, context) { this.__observers__ = this.__observers__ || []; context = context || null; var i = this.countObservers(); while (i--) { if (this.__observers__[i]._block === observer && this.__observers__[i]._context === context) { this.__observers__.splice(i,1); return; } } }, removeObservers: function() { this.__observers__ = []; }, countObservers: function() { return (this.__observers__ = this.__observers__ || []).length; }, notifyObservers: function() { if (!this.isChanged()) return; var i = this.countObservers(), observer, block, context; while (i--) { observer = this.__observers__[i]; block = observer._block; context = observer._context; if (JS.isFn(block)) block.apply(context || null, arguments); else block[context || JS.Observable.DEFAULT_METHOD].apply(block, arguments); } }, setChanged: function(state) { this.__changed__ = !(state === false); }, isChanged: function() { if (this.__changed__ === undefined) this.__changed__ = true; return !!this.__changed__; } }); JS.Observable.include({ subscribe: JS.Observable.instanceMethod('addObserver'), unsubscribe: JS.Observable.instanceMethod('removeObserver') }, true); JS.State = new JS.Module('State', { __getState__: function(state) { return (typeof state === 'object' && state) || (typeof state === 'string' && ((this.states || {})[state] || {})) || {}; }, setState: function(state) { this.__state__ = this.__getState__(state); JS.State.addMethods(this.__state__, this.klass); }, inState: function() { var i = arguments.length; while (i--) { if (this.__state__ === this.__getState__(arguments[i])) return true; } return false; }, extend: { stub: function() { return this; }, buildStubs: function(stubs, collection, states) { var state, method; for (state in states) { collection[state] = {}; for (method in states[state]) stubs[method] = this.stub; } }, buildCollection: function(module, states) { var stubs = {}, collection = {}, superstates = module.lookup('states').pop() || {}, state, klass, methods, name; this.buildStubs(stubs, collection, states); this.buildStubs(stubs, collection, superstates); for (state in collection) { klass = (superstates[state]||{}).klass; klass = klass ? new JS.Class(klass, states[state]) : new JS.Class(states[state]); methods = {}; for (name in stubs) { if (!klass.prototype[name]) methods[name] = stubs[name]; } klass.include(methods, false); collection[state] = new klass; } if (module.__res__) this.addMethods(stubs, module.__res__.klass); return collection; }, addMethods: function(state, klass) { if (!klass) return; var methods = {}, p = klass.prototype, method; for (method in state) { if (p[method]) continue; p[method] = klass.__mod__.__fns__[method] = this.wrapped(method); } }, wrapped: function(method) { return function() { var func = (this.__state__ || {})[method]; return func ? func.apply(this, arguments): this; }; } } }); JS.Module.include({define: (function(wrapped) { return function(name, block) { if (name === 'states' && typeof block === 'object') arguments[1] = JS.State.buildCollection(this, block); return wrapped.apply(this, arguments); }; })(JS.Module.prototype.define)}, true);_application/x-javascriptO,bplist00z{X$versionX$objectsY$archiverT$top("()0!12TUVWXYZ[\]^_`abcdefghijklmnoptuU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1&'#$%&[NS.relativeWNS.base_1https://cdn.othermedia.com/ojay/0.4.1/js-class.js*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#ADڅ3456EWNS.keysZNS.objects%789:;<=>?@ABCD FGHIJKLMNOPQRS !"#$VServerZConnectionZKeep-Alive_Content-EncodingTVary\Content-TypeWExpires]Cache-Control]Accept-Ranges_X-Ua-Compatible]Last-ModifiedWX-CacheTDate^Content-LengthVApacheZKeep-Alive_timeout=2, max=100Tgzip_Accept-Encoding,U_application/x-javascript_Fri, 08 Oct 2021 17:18:04 GMT_max-age=315360000Ubytes]IE=EmulateIE7_Thu, 25 Jun 2009 14:45:23 GMT_MISS from cdn.othermedia.com_Tue, 11 Oct 2011 17:18:04 GMTU12877*+qr_NSMutableDictionaryqs/\NSDictionary*+vw_NSHTTPURLResponsexy/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiver|}_WebResourceResponse#-27bh"-6<?ENWY`hsu #1CQY^mt0Oouz~_1https://cdn.othermedia.com/ojay/0.4.1/js-class.jsrstuO#/* Copyright (c) 2007-2008 the OTHER media Limited Licensed under the BSD license, http://ojay.othermedia.org/license.html Version: 0.4.1 Build: source */ /** *

Returns an object that wraps a collection of DOM element references by parsing * the given query using a CSS selector engine.

* *

Aliased as $().

* * @params {String|Array} query * @returns {DomCollection} */ var Ojay = function() { var elements = [], arg, i, n; for (i = 0, n = arguments.length; i < n; i++) { arg = arguments[i]; if (typeof arg == 'string') arg = Ojay.cssEngine.query(arg); if (arg.toArray) arg = arg.toArray(); if (!(arg instanceof Array)) arg = [arg]; elements = elements.concat(arg); } return new Ojay.DomCollection(elements.unique()); }; Ojay.VERSION = '0.4.1'; Array.from = JS.array; Function.prototype.bind = function() { return JS.bind.apply(JS, [this].concat(JS.array(arguments))); }; (function(Dom) { JS.extend(Ojay, /** @scope Ojay */{ /** *

Returns an Ojay Collection containing zero or one element that matches the ID. Used * for situations where IDs contains dots, slashes, etc.

* @param {String} id * @returns {DomCollection} */ byId: function(id) { var element = document.getElementById(id); return new this.DomCollection(element ? [element] : []); }, /** *

Changes the alias of the Ojay() function to the given alias. * If the alias is already the name of an existing function, that function will be * stored and overridden. The next call to changeAlias or surrenderAlias * will restore the original function.

* @param {String} alias */ changeAlias: function(alias) { this.surrenderAlias(); this.ALIAS = String(alias); this.__alias = (typeof window[this.ALIAS] == 'undefined') ? null : window[this.ALIAS]; window[this.ALIAS] = this; }, /** *

Gives control of the shorthand function back to whichever script implemented * it before Ojay. After using this function, use the Ojay() function * instead of the shorthand.

* @returns {Boolean} */ surrenderAlias: function() { if (this.__alias === null) { if (this.ALIAS) delete window[this.ALIAS]; return false; } window[this.ALIAS] = this.__alias; return true; }, /** *

Tells Ojay to trace calls to the methods you name. Only accepts methods on * Ojay.DomCollection.prototype.

* @param {String} */ log: function() { Array.from(arguments).forEach(function(method) { this[method] = this[method].traced(method + '()'); }, Ojay.DomCollection.prototype); }, /** *

Returns an object with width and height properties specifying the size of the * document.

* @returns {Object} */ getDocumentSize: function() { return { width: Dom.getDocumentWidth(), height: Dom.getDocumentHeight() }; }, /** *

Returns an object with left and top properties specifying the scroll offsets * document.

* @returns {Object} */ getScrollOffsets: function() { return { left: Dom.getDocumentScrollLeft(), top: Dom.getDocumentScrollTop() }; }, /** *

Returns an object with width and height properties specifying the size of the * viewport.

* @returns {Object} */ getViewportSize: function() { return { width: Dom.getViewportWidth(), height: Dom.getViewportHeight() }; }, /** *

Returns a Region object representing the currently visible area of * the document within the browser viewport.

* @returns {Region} */ getVisibleRegion: function() { var viewport = this.getViewportSize(), scrolls = this.getScrollOffsets(); return new this.Region({ top: scrolls.top, bottom: scrolls.top + viewport.height, left: scrolls.left, right: scrolls.left + viewport.width }); } }); })(YAHOO.util.Dom); Ojay.changeAlias('$'); /** *

This object contains definitions for Array instance methods defined * by Mozilla in JavaScript versions 1.6 and 1.8. They are applied to the Array * prototype as required to bring all browsers up to scratch.

* *

Definitions are taken from Mozilla's * implementations (made available under the MIT license).

*/ Ojay.ARRAY_METHODS = { /** *

Returns the first index at which a given element can be found in the array, or * -1 if it is not present.

*/ indexOf: function(elt /*, from*/) { var len = this.length; var from = Number(arguments[1]) || 0; from = (from < 0) ? Math.ceil(from) : Math.floor(from); if (from < 0) from += len; for (; from < len; from++) { if (from in this && this[from] === elt) return from; } return -1; }, /** *

Returns the last index at which a given element can be found in the array, or * -1 if it is not present. The array is searched backwards, * starting at fromIndex.

*/ lastIndexOf: function(elt /*, from*/) { var len = this.length; var from = Number(arguments[1]); if (isNaN(from)) { from = len - 1; } else { from = (from < 0) ? Math.ceil(from) : Math.floor(from); if (from < 0) from += len; else if (from >= len) from = len - 1; } for (; from > -1; from--) { if (from in this && this[from] === elt) return from; } return -1; }, /** *

filter calls a provided callback function once for each element in an * array, and constructs a new array of all the values for which callback * returns a true value. callback is invoked only for indexes of * the array which have assigned values; it is not invoked for indexes which have been * deleted or which have never been assigned values. Array elements which do not pass * the callback test are simply skipped, and are not included in the new array.

* *

callback is invoked with three arguments: the value of the element, the * index of the element, and the Array object being traversed.

* *

If a thisObject parameter is provided to filter, it will be * used as the this for each invocation of the callback. If it is not provided, * or is null, the global object associated with callback is used instead.

* *

filter does not mutate the array on which it is called.

* *

The range of elements processed by filter is set before the first invocation of * callback. Elements which are appended to the array after the call to * filter begins will not be visited by callback. If existing elements * of the array are changed, or deleted, their value as passed to callback will * be the value at the time filter visits them; elements that are deleted are * not visited.

*/ filter: function(fun /*, thisp*/) { var len = this.length; if (typeof fun != "function") throw new TypeError(); var res = new Array(); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) { var val = this[i]; // in case fun mutates this if (fun.call(thisp, val, i, this)) res.push(val); } } return res; }, /** *

forEach executes the provided function (callback) once for each * element present in the array. callback is invoked only for indexes of the * array which have assigned values; it is not invoked for indexes which have been * deleted or which have never been assigned values.

* *

callback is invoked with three arguments: the value of the element, the * index of the element, and the Array object being traversed.

* *

If a thisObject parameter is provided to forEach, it will be used * as the this for each invocation of the callback. If it is not provided, or is * null, the global object associated with callback is used instead.

* *

forEach does not mutate the array on which it is called.

* *

The range of elements processed by forEach is set before the first * invocation of callback. Elements which are appended to the array after the call * to forEach begins will not be visited by callback. If existing elements * of the array are changed, or deleted, their value as passed to callback will be * the value at the time forEach visits them; elements that are deleted are not * visited.

*/ forEach: function(fun /*, thisp*/) { var len = this.length; if (typeof fun != "function") throw new TypeError(); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) fun.call(thisp, this[i], i, this); } }, /** *

every executes the provided callback function once for each element * present in the array until it finds one where callback returns a * false value. If such an element is found, the every method * immediately returns false. Otherwise, if callback returned a * true value for all elements, every will return true. * callback is invoked only for indexes of the array which have assigned * values; it is not invoked for indexes which have been deleted or which have never * been assigned values.

* *

callback is invoked with three arguments: the value of the element, * the index of the element, and the Array object being traversed.

* *

If a thisObject parameter is provided to every, it will be * used as the this for each invocation of the callback. If it is not * provided, or is null, the global object associated with callback * is used instead.

* *

every does not mutate the array on which it is called.

* *

The range of elements processed by every is set before the first * invocation of callback. Elements which are appended to the array after * the call to every begins will not be visited by callback. If * existing elements of the array are changed, their value as passed to callback * will be the value at the time every visits them; elements that are deleted * are not visited. every acts like the "for all" quantifier in mathematics. * In particular, for an empty array, it returns true. (It is vacuously true * that all elements of the empty set satisfy any given condition.)

*/ every: function(fun /*, thisp*/) { var len = this.length; if (typeof fun != "function") throw new TypeError(); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this && !fun.call(thisp, this[i], i, this)) return false; } return true; }, /** *

map calls a provided callback function once for each element in an array, * in order, and constructs a new array from the results. callback is invoked * only for indexes of the array which have assigned values; it is not invoked for * indexes which have been deleted or which have never been assigned values.

* *

callback is invoked with three arguments: the value of the element, the * index of the element, and the Array object being traversed.

* *

If a thisObject parameter is provided to map, it will be used as * the this for each invocation of the callback. If it is not provided, or is * null, the global object associated with callback is used instead.

* *

map does not mutate the array on which it is called.

* *

The range of elements processed by map is set before the first invocation * of callback. Elements which are appended to the array after the call to * map begins will not be visited by callback. If existing elements of * the array are changed, or deleted, their value as passed to callback will be * the value at the time map visits them; elements that are deleted are not * visited.

*/ map: function(fun /*, thisp*/) { var len = this.length; if (typeof fun != "function") throw new TypeError(); var res = new Array(len); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) res[i] = fun.call(thisp, this[i], i, this); } return res; }, /** *

some executes the callback function once for each element present in the * array until it finds one where callback returns a true value. If such * an element is found, some immediately returns true. Otherwise, * some returns false. callback is invoked only for indexes of * the array which have assigned values; it is not invoked for indexes which have been * deleted or which have never been assigned values.

* *

callback is invoked with three arguments: the value of the element, the * index of the element, and the Array object being traversed.

* *

If a thisObject parameter is provided to some, it will be used as * the this for each invocation of the callback. If it is not provided, or is * null, the global object associated with callback is used instead.

* *

some does not mutate the array on which it is called.

* *

The range of elements processed by some is set before the first invocation * of callback. Elements that are appended to the array after the call to * some begins will not be visited by callback. If an existing, unvisited * element of the array is changed by callback, its value passed to the visiting * callback will be the value at the time that some visits that element's index; * elements that are deleted are not visited.

*/ some: function(fun /*, thisp*/) { var len = this.length; if (typeof fun != "function") throw new TypeError(); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this && fun.call(thisp, this[i], i, this)) return true; } return false; }, /** *

Apply a function simultaneously against two values of the array (from * left-to-right) as to reduce it to a single value.

* *

reduce executes the callback function once for each element present in the * array, excluding holes in the array, receiving four arguments: the initial value (or * value from the previous callback call), the value of the current element, the current * index, and the array over which iteration is occurring.

*/ reduce: function(fun /*, initial*/) { var len = this.length; if (typeof fun != "function") throw new TypeError(); // no value to return if no initial value and an empty array if (len == 0 && arguments.length == 1) throw new TypeError(); var i = 0; if (arguments.length >= 2) { var rv = arguments[1]; } else { do { if (i in this) { rv = this[i++]; break; } // if array contains no values, no initial value to return if (++i >= len) throw new TypeError(); } while (true); } for (; i < len; i++) { if (i in this) rv = fun.call(null, rv, this[i], i, this); } return rv; }, /** *

Apply a function simultaneously against two values of the array (from * right-to-left) as to reduce it to a single value.

* *

reduceRight executes the callback function once for each element present in * the array, excluding holes in the array, receiving four arguments: the initial value (or * value from the previous callback call), the value of the current element, the current * index, and the array over which iteration is occurring.

*/ reduceRight: function(fun /*, initial*/) { var len = this.length; if (typeof fun != "function") throw new TypeError(); // no value to return if no initial value, empty array if (len == 0 && arguments.length == 1) throw new TypeError(); var i = len - 1; if (arguments.length >= 2) { var rv = arguments[1]; } else { do { if (i in this) { rv = this[i--]; break; } // if array contains no values, no initial value to return if (--i < 0) throw new TypeError(); } while (true); } for (; i >= 0; i--) { if (i in this) rv = fun.call(null, rv, this[i], i, this); } return rv; }, /** *

Returns a new array containing all the elements of the original array but with * any duplicate entries removed.

* @returns {Array} */ unique: function() { var results = [], i, n, arg; for (i = 0, n = this.length; i < n; i++) { arg = this[i]; if (results.indexOf(arg) == -1) results.push(arg); } return results; }, /** *

A shorthand for array.filter(func).length.

*/ count: function(fun, thisp) { return this.filter(fun, thisp).length; } }; JS.extend(Array.prototype, Ojay.ARRAY_METHODS); /** * Functional extensions: Copyright (c) 2005-2008 Sam Stephenson / the Prototype team, * released under an MIT-style license. */ JS.extend(Function.prototype, /** @scope Function.prototype */{ /** *

'Masks' the internals of a function by setting its toString and valueOf methods * to return the masking function instead of the receiver. This can be used to make sure, * for example, that functions like JS.Class's callSuper() that rely on stringifying * functions for intrspection still work as desired.

* @param {Function} wrapper * @returns {Function} */ _mask: function(wrapper) { this.valueOf = function() { return wrapper; }; this.toString = function() { return wrapper.toString(); }; return this; }, /** *

Returns a new function that does the same thing as the original function, but has * some of its arguments preset. A contrived example:

* *
    var add = function(a, b) { return a + b; };
     *     add(3, 5)  // --> 8
     *     
     *     var add12 = add.partial(12);  // 'a' is preset to 12
     *     add12(7)  // --> 19
* *

More information in the * Prototype documentation. (Prototype calls this method curry, though * that's not strictly what it does.)

* * @returns {Function} */ partial: function() { if (!arguments.length) return this; var method = this, args = Array.from(arguments); return function() { return method.apply(this, args.concat(Array.from(arguments))); }._mask(this); }, /** *

Returns a copy of the function that is self-currying, i.e. every time you call it, it * returns a curried version of itself until it's got all its required arguments.

* *
    var adder = function(a,b,c) {
     *         return a + b + c;
     *     };
     *     
     *     var add = adder.curry();
     *     
     *     add(1)(2)(3)  // --> 6
     *     add(7,8)(23)  // --> 38
* * @param {Number} n * @returns {Function} */ curry: function(n) { var method = this, n = n || this.length; return function() { if (arguments.length >= n) return method.apply(this, arguments); return method.partial.apply(arguments.callee, arguments); }._mask(this); }, /** *

Allows you to 'intercept' calls to existing functions and manipulate their input and * output, providing aspect-oriented programming functionality. More information and * examples in the Prototype docs.

* @param {Function} wrapper * @returns {Function} */ wrap: function(wrapper) { var method = this; return function() { return wrapper.apply(this, [method.bind(this)].concat(Array.from(arguments))); }._mask(this); }, /** *

Returns a version of the function that, rather taking some argument foo as * its first argument, can be applied as a method of foo.

* *
    var hexToDec = function(string) {
     *         var number = ... // convert hex string to decimal
     *         return number;
     *     };
     *     
     *     hexToDec('ff')   // --> 255
     *     
     *     String.prototype.hexToDec = hexToDec.methodize();
     *     'ff'.hexToDec()  // --> 255
* * @returns {Function} */ methodize: function() { if (this._methodized) return this._methodized; var method = this; return this._methodized = function() { return method.apply(null, [this].concat(Array.from(arguments))); }._mask(this); }, /** *

Effectively does the opposite of methodize: it converts a function from a * method that uses this to refer to its operand, into one that takes the operand * as its first argument. This is useful for building iterators, amongst other things.

* *
    var upper = "".toUpperCase.functionize();
     *     var strings = ['foo', 'bar', 'baz', ... ];
     *     
     *     var caps = strings.map(upper);
     *     // --> ['FOO', 'BAR', 'BAZ', ... ]
* * @returns {Function} */ functionize: function() { if (this._functionized) return this._functionized; var method = this; return this._functionized = function() { var args = Array.from(arguments); return method.apply(args.shift(), args); }._mask(this); }, /** *

Returns a function that returns the result of applying the function to its arguments, * but that logs its input and output to the Firebug console. Derived from a similar function * in Oliver Steele's Functional library.

* * Copyright: Copyright 2007 by Oliver Steele. All rights reserved. * http://osteele.com/sources/javascript/functional/ * * @param {String} name * @param {String} func * @returns {Function} */ traced: function(name, func) { var method = this, name = name || this, func = func || 'info'; return function() { window.console && console[func](name, ' called on ', this, ' with ', arguments); var result = method.apply(this, arguments); window.console && console[func](name, ' -> ', result); return result; }._mask(this); }, /** *

Returns a copy of the function that will only run the specified number of times. Note * that if the function is an instance method, it will run the given number of times in total, * not per instance.

* @param {Number} times * @returns {Function} */ runs: function(times) { var method = this, count = 0; return function() { return (count++ < times) ? method.apply(this, arguments) : undefined; }._mask(this); } }); /** * String extensions: Copyright (c) 2005-2008 Sam Stephenson / the Prototype team, * released under an MIT-style license. */ String.SCRIPT_FRAGMENT = ']*>([\\S\\s]*?)<\/script>'; JS.extend(String.prototype, /** @scope String.prototype */{ /** *

Returns an array containing the content of any <script> tags present * in the string.

* @returns {Array} */ extractScripts: function() { var matchAll = new RegExp(String.SCRIPT_FRAGMENT, 'img'); var matchOne = new RegExp(String.SCRIPT_FRAGMENT, 'im'); return (this.match(matchAll) || []).map(function(scriptTag) { return (scriptTag.match(matchOne) || ['', ''])[1]; }); }, /** *

Extracts the content of any <script> tags present in the string and * evals them. Returns an array containing the return value of each evaluated * script.

*/ evalScripts: function() { return this.extractScripts().map(function(script) { return eval(script); }); }, /** *

Returns the result of parsing the string as JSON. Requires the YUI JSON utility.

* @returns {Object|Array} */ parseJSON: function() { return YAHOO.lang.JSON.parse(this.valueOf()); }, /** *

Returns a copy of the string with all <script> tags removed.

* @returns {String} */ stripScripts: function() { return this.replace(new RegExp(String.SCRIPT_FRAGMENT, 'img'), ''); }, /** *

Returns a copy of the string with all HTML tags removed.

* @returns {String} */ stripTags: function() { return this.replace(/<\/?[^>]+>/gi, '').trim(); }, /** *

Returns a copy of the string with all leading and trailing whitespace removed.

* @returns {String} */ trim: YAHOO.lang.trim.methodize() }); /** * @overview *

Ojay adds all the single-number functions in Math as methods to Number. * The following methods can all be called on numbers:

* *
abs, acos, asin, atan, ceil, cos, exp, floor, log, pow, round, sin, sqrt, tan
*/ 'abs acos asin atan ceil cos exp floor log pow round sin sqrt tan'.split(/\s+/). forEach(function(method) { Number.prototype[method] = Math[method].methodize(); }); /** *

Calls the given block in the scope of context a given number of * times. The block receives the iteration index each time it is called.

* @param {Function} block * @param {Object} context */ Number.prototype.times = function(block, context) { if (this < 0) return; for (var i = 0; i < this; i++) block.call(context || null, i); }; /** *

Returns true iff the number is between a and b inclusive. * To test the range without including the end points, pass false as the third * argument.

* @param {Number} a * @param {Number} b * @param {Boolean} inclusive * @returns {Boolean} */ Number.prototype.between = function(a, b, inclusive) { if (this > a && this < b) return true; return (this == a || this == b) ? (inclusive !== false) : false; }; /** * Copyright (c) 2007-2008 James Coglan * http://blog.jcoglan.com/reiterate/ * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ Function.from = function(iterator) { if (iterator.toFunction) return iterator.toFunction(); if (typeof iterator == 'function') return iterator; if (typeof iterator == 'object') return Function.fromObject(iterator); return function(x) { return x; }; }; String.prototype.toFunction = function() { var properties = this.split('.'); if (!properties[0]) return function(x) { return x; }; return function(o) { var object, member = o, key; for (var i = 0, n = properties.length; i < n; i++) { key = properties[i]; object = member; member = object[key]; if (typeof member == 'function') member = member.apply(object); } return member; }; }; Array.prototype.toFunction = function() { var method = this[0], args = this.slice(1); if (!method) return function(x) { return x; }; return function(o) { var fn = (typeof method == 'function') ? method : o[method]; return (typeof fn == 'function') ? fn.apply(o, args) : undefined; }; }; Function.fromObject = function(object) { var keys = []; for (var field in object) { if (object.hasOwnProperty(field)) keys.push(field); } if (keys.length === 0) return function(x) { return x; }; return function(o) { var result = true, key, fn, args; for (var i = 0, n = keys.length; i < n; i++) { key = keys[i]; fn = o[key]; args = object[key]; if (typeof fn == 'function' && !(args instanceof Array)) args = [args]; result = result && ((typeof fn == 'function') ? fn.apply(o, args) : fn == args); } return result; }; }; 'filter forEach every map some'.split(/\s+/).forEach(function(method) { this[method] = this[method].wrap(function(fn, iterator, thisObject) { if (iterator) iterator = Function.from(iterator); return fn(iterator, thisObject); }); }, Array.prototype); /** * @overview *

This file contains adapter objects that allow Ojay to use a variety of CSS selector * backends. Given that CSS engines are now being released as standalone libraries, it * makes sense to let people choose which one they want to use.

* *

Ojay includes support for YAHOO.util.Selector, Sizzle and * peppy engines, but it is trivial to add support for others.

*/ Ojay.Selectors = { Native: { /** * @param {String} selector * @param {HTMLElement} context * @returns {Array} */ query: function(selector, context) { return Array.from((context || document).querySelectorAll(selector)); }, /** * @param {HTMLElement} node * @param {String} selector * @returns {Boolean} */ test: function(node, selector) { var results = this.query(selector, node.parentNode); return results.indexOf(node) != -1; } }, Yahoo: { /** * @param {String} selector * @param {HTMLElement} context * @returns {Array} */ query: function(selector, context) { return YAHOO.util.Selector.query(selector, context); }, /** * @param {HTMLElement} node * @param {String} selector * @returns {Boolean} */ test: function(node, selector) { return YAHOO.util.Selector.test(node, selector); } }, Ext: { /** * @param {String} selector * @param {HTMLElement} context * @returns {Array} */ query: function(selector, context) { return Ext.DomQuery.select(selector, context); }, /** * @param {HTMLElement} node * @param {String} selector * @returns {Boolean} */ test: function(node, selector) { return Ext.DomQuery.is(node, selector); } }, Sizzle: { /** * @param {String} selector * @param {HTMLElement} context * @returns {Array} */ query: function(selector, context) { return Sizzle(selector, context); }, /** * @param {HTMLElement} node * @param {String} selector * @returns {Boolean} */ test: function(node, selector) { return Sizzle.filter(selector, [node]).length === 1; } }, Peppy: { /** * @param {String} selector * @param {HTMLElement} context * @returns {Array} */ query: function(selector, context) { return peppy.query(selector, context); }, /** * @param {HTMLElement} node * @param {String} selector * @returns {Boolean} */ test: function(node, selector) { var results = peppy.query(selector, node, true); return results.indexOf(node) != -1; } } }; // Default choice is YUI, or qSA if available Ojay.cssEngine = document.querySelectorAll ? Ojay.Selectors.Native : Ojay.Selectors.Yahoo; (function(Event) { JS.extend(Ojay, /** @scope Ojay */{ /** *

Pre-built callback that stops the default browser reaction to an event.

* @param {DomCollection} element * @param {Event} evnt */ stopDefault: function(element, evnt) { Event.preventDefault(evnt); }, /** *

Pre-built callback that stops the event bubbling up the DOM tree.

* @param {DomCollection} element * @param {Event} evnt */ stopPropagate: function(element, evnt) { Event.stopPropagation(evnt); }, /** *

Pre-built callback that both stops the default behaviour and prevents bubbling.

* @param {DomCollection} element * @param {Event} evnt */ stopEvent: function(element, evnt) { Ojay.stopDefault(element, evnt); Ojay.stopPropagate(element, evnt); }, /** *

Returns an event callback that checks the event target against each given CSS * selector and fires all the applicable callbacks. Based on prior ideas from:

* *
    *
  • http://icant.co.uk/sandbox/eventdelegation/
  • *
  • http://www.danwebb.net/2008/2/8/event-delegation-made-easy-in-jquery
  • *
* *

To delegate events, supply an object mapping CSS selectors to callback functions. * when the event fires, the target is compared against all given selectors all all * applicable callbacks are fired. If the secord parameter is set to true, * the delegator will crawl back up the DOM tree until it finds an element that contains * the target and matches the given selector.

* * @param {Object} map * @param {Boolean} includeAncestors * @returns {Function} */ delegateEvent: function(map, includeAncestors) { return function(element, evnt) { var target = evnt.getTarget(), candidate; for (var selector in map) { if (!target.matches(selector) && !includeAncestors) continue; candidate = target; if (includeAncestors) while (candidate && !candidate.matches(selector)) { candidate = Ojay(candidate.node.parentNode); if (candidate.node == document.body) candidate = null; } if (candidate) Function.from(map[selector]).call(this, candidate, evnt); } }; }, _getTarget: function() { return Ojay(Event.getTarget(this)); } }); Ojay.stopDefault.method = Ojay.stopDefault.partial(null).methodize(); Ojay.stopPropagate.method = Ojay.stopPropagate.partial(null).methodize(); Ojay.stopEvent.method = Ojay.stopEvent.partial(null).methodize(); ['onDOMReady', 'onContentReady', 'onAvailable'].forEach(function(method) { Ojay[method] = Event[method].bind(Event); }); })(YAHOO.util.Event); /** *

The Ojay.Observable module extends the JS.Observable module with an * on() method that behaves similarly to DomCollection#on(), used for * monitoring DOM events. It uses addObserver() to set up an interface through * which an object may publish named events, and other objects can listen to such events, * just as for DOM events. Here's an example of a class that uses the module:

* *
    var Player = new JS.Class({
 *         include: Ojay.Observable,
 *         
 *         play: function() {
 *             this.startTime = this.getTime();
 *             this.notifyObservers('start');
 *         },
 *         
 *         pause: function() {
 *             var elapsed = this.getTime() - this.startTime;
 *             this.notifyObservers('pause', elapsed);
 *         },
 *         
 *         getTime: function() {
 *             return Number(new Date()) / 1000;
 *         }
 *     });
* *

The getTime() method simply returns the current timestamp in seconds. The * play() method records the current time and fires the start event by using * notifyObservers() to send a message to its observers. The pause() * method simply publishes a pause event that sends the elapsed time to any * listeners.

* *

Some client code to listen to one of these objects might look like this:

* *
    var p = new Player();
 *     
 *     p.on('start', function(player) {
 *         alert(player.startTime);
 *     });
 *     
 *     p.on('pause', function(player, timeElapsed) {
 *         alert(timeElapsed);
 *     });
* *

All listeners receive the object that fired the event as their first argument, and * any data published by said object with the event as the subsequent arguments. An optional * third argument to on() specifies the execution context of the listener function, * so for example:

* *
    p.on('start', function() {
 *         // this === someObject
 *     }, someObject);
* *

All calls to on() return a MethodChain object that, by default, will * fire on the object publishing the event, so the following:

* *
    p.on('start').pause();
* *

Will cause p to call its pause() method whenever its start * event is fired.

* *

For further information on this module, see the JS.Observable documentation at * http://jsclass.jcoglan.com/observable.html.

* * @module Observable */ Ojay.Observable = new JS.Module('Ojay.Observable', { include: JS.Observable, /** *

Registers an event listener on the object. Takes an event name and an optional * callback function, and returns a MethodChain that will fire on the source * object. The callback receives the source object as the first parameter.

* @param {String} eventName * @param {Function} callback * @param {Object} scope * @returns {MethodChain} */ on: function(eventName, callback, scope) { var chain = new JS.MethodChain; if (callback && typeof callback != 'function') scope = callback; this.addObserver(function() { var args = Array.from(arguments), message = args.shift(); if (message != eventName) return; if (typeof callback == 'function') callback.apply(scope || null, args); chain.fire(scope || args[0]); }, this); return chain; }, /** *

Notifies all observers of an object, sending them the supplied arguments. Use * the first argument to specify the event name for handlers registered using * Observable#on().

* @returns {Observable} */ notifyObservers: function() { var args = Array.from(arguments), receiver = (args[1]||{}).receiver || this; if (receiver == this) args.splice(1, 0, receiver); else args[1] = receiver; this.callSuper.apply(this, args); args[1] = {receiver: receiver}; var classes = this.klass.ancestors(), klass; while (klass = classes.pop()) klass.notifyObservers && klass.notifyObservers.apply(klass, args); return this; }, extend: /** @scope Ojay.Observable */{ /** *

Any module that includes Observable is also extended * using Observable.

* @param {Class|Module} base */ included: function(base) { base.extend(this); } } }); Ojay.Observable.extend(Ojay.Observable); (function(Ojay, Dom) { /** *

Wraps collections of DOM element references with an API for manipulation of page * elements. Includes methods for getting/setting class names and style attributes, * traversing the DOM, setting up event handlers, and performing animation.

* @constructor * @class DomCollection */ Ojay.DomCollection = new JS.Class('Ojay.DomCollection', /** @scope Ojay.DomCollection.prototype */{ /** * @param {Array} collection * @returns {DomCollection} */ initialize: function(collection) { this.length = 0; for (var i = 0, n = collection.length, nodeType, push = [].push; i < n; i++) { nodeType = collection[i].nodeType; if (nodeType === Ojay.HTML.ELEMENT_NODE || nodeType === Ojay.HTML.DOCUMENT_NODE || collection[i] == window) push.call(this, collection[i]); } this.node = this[0]; return this; }, /** *

Returns the elements of the collection as a native Array type. Can optionally take * a function to convert values as the new array is constructed.

* @param {Function} via * @returns {Array} */ toArray: function(via) { if (via) via = Function.from(via); var results = [], i, n = this.length; for (i = 0; i < n; i++) results.push(via ? via(this[i]) : this[i]); return results; }, /** *

Returns a DomCollection wrapping the nth element in the current * collection.

* @param {Number} n * @returns {DomCollection} */ at: function(n) { n = Number(n).round(); var item = (n >= 0 && n < this.length) ? [this[n]] : []; return new this.klass(item); }, /** *

Registers event listeners on all the members of the collection. You must supply at * least the name of the event to listen for, and you can supply a callback function and * (optionally) its scope as well. This method returns a MethodChain so you can * write more sentence-like code without needing to write explicit callback functions. Some * examples:

* *
    Ojay('p').on('click').setStyle({textDecoration: 'underline'});
         *     
         *     Ojay('p').on('mouseout').hide().parents().setStyle( ... );
         *     
         *     Ojay('li').on('click')._('h1#title').setStyle({color: '#f00'});
* *

When using chaining like this, the method chain is fired only on the element that * triggers each event, not on the whole collection you called on() on.

* *

When using explicit callback functions, the callback receives on Ojay object * wrapping the element that triggered the event, and the event object as arguments. If you * supply your own scope parameter, this refers to your supplied object inside the * callback.

* *
    Ojay('div').on('click', function(element, ev) {
         *         // 'this' does not refer to anything useful
         *     });
         *     
         *     Ojay('p').on('mouseout', function(element, ev) {
         *         // 'this' refers to the object 'someObject'
         *     }, someObject);
* *

Even when you supply an explicit function, on() returns a MethodChain * so you can use the chaining feature as well. You can store a reference to this collector * so you can modify the event handler at a later time, without actually creating any new * handlers:

* *
    var chain = Ojay('a.external').on('click');
         *
         *     // somewhere else...
         *     chain.addClass('clicked');
* *

Any a.external will then gain the class name when it is clicked.

* *

There is one final subtlety: if you supply a second argument that is NOT a function, it * will be used as the base object for any chain firings. e.g.:

* *
    // When these <p>s are clicked, the <h1> changes
         *     Ojay('p.changer').on('click', Ojay('h1')).setStyle({textTransform: 'uppercase'})
* * *

Ojay gives you easy control of how the browser should respond to events. Inside your * callback function, you can prevent the event's default behaviour and stop it bubbling up * the DOM like so:

* *
    Ojay('a').on('click', function(element, ev) {
         *         ev.stopDefault();
         *         // ... your custom behaviour
         *     });
* *

stopDefault stops the browser running the default behaviour for the event, e.g. * loading a new page when a link is clicked. The method stopPropagate stops the * event bubbling, and stopEvent does both. If all your callback does is call one * of these methods, you can use on of Ojay's pre-stored callbacks instead:

* *
    Ojay('a').on('click', Ojay.stopDefault).setStyle({textDecoration: 'underline'});
* *

You can use stopDefault, stopPropagate and stopEvent in this * manner. Using these is recommended over writing your own callbacks to do this, as creating * new identical functions wastes memory.

* * @param {String} eventName * @param {Function} callback * @param {Object} scope * @returns {MethodChain} */ on: function(eventName, callback, scope) { var chain = new JS.MethodChain; if (callback && typeof callback != 'function') scope = callback; var handler = function(evnt) { if (evnt.eventName !== undefined && evnt.eventName != eventName) return; var wrapper = Ojay(this); evnt.stopDefault = Ojay.stopDefault.method; evnt.stopPropagate = Ojay.stopPropagate.method; evnt.stopEvent = Ojay.stopEvent.method; evnt.getTarget = Ojay._getTarget; if (typeof callback == 'function') callback.call(scope || null, wrapper, evnt); chain.fire(scope || wrapper); }; if (/:/.test(eventName)) { for (var i = 0, n = this.length; i < n; i++) (function(element) { var wrapped = handler.bind(element); if (element.addEventListener) { element.addEventListener('dataavailable', wrapped, false); } else { element.attachEvent('ondataavailable', wrapped); element.attachEvent('onfilterchange', wrapped); } })(this[i]); } else { YAHOO.util.Event.on(this, eventName, handler); } return chain; }, /** *

Fires a custom event on each element in the collection, firing any custom event * handlers that have been registered on these elements. The first argument should be * the name of the event to fire, and the second argument (optional) should be a boolean * indicating whether the event should bubble or not (this defaults to true).

* @param {String} eventName * @param {Object} data * @param {Boolean} bubble * @returns {DomCollection} */ trigger: function(eventName, data, bubble) { bubble = (bubble === undefined) ? true : false; for (var i = 0, n = this.length; i < n; i++) (function(element) { if (element == document && document.createEvent && !element.dispatchEvent) element = document.documentElement; var event; if (document.createEvent) { event = document.createEvent('HTMLEvents'); event.initEvent('dataavailable', bubble, true); } else { event = document.createEventObject(); event.eventType = bubble ? 'ondataavailable' : 'onfilterchange'; } event.eventName = eventName; JS.extend(event, data || {}); try { document.createEvent ? element.dispatchEvent(event) : element.fireEvent(event.eventType, event); } catch (e) {} })(this[i]); return this; }, /** *

Runs an animation on all the elements in the collection. The method expects you to supply * at least an object specifying CSS properties to animate, and the duration of the animation.

* *
   Ojay('#some-list li').animate({marginLeft: {to: 200}}, 1.5)
* *

Functions can be used for any of these values to apply a different animation to each element * in the collection. Each function is passed the element's position in the collection (i) * and the element itself (el), and is evaluated just before the animation begins. el * is actually a DomCollection wrapping a single element. For example, to animate some * list elements out by a staggered amount, do:

* *
   Ojay('#some-list li').animate({
         *        marginLeft: {
         *            to: function(i, el) { return 40 * i; }
         *        }
         *    }, 2.0);
* *

The functions can appear at any level of the parameters object, so you could write * the above as:

* *
   Ojay('#some-list li').animate(function(i, el) {
         *        return {
         *            marginLeft: {to: 40 * i}
         *        };
         *    }, 2.0);
* *

or

* *
   Ojay('#some-list li').animate({
         *        marginLeft: function(i, el) {
         *            return {to: 40 * i};
         *        }
         *    }, 2.0);
* *

This allows for highly flexible animation definitions. You can also specify a function as * the duration parameter, so that each element takes a different time to animate:

* *
   Ojay('#some-list li').animate({marginLeft: {to: 200}},
         *            function(i) { return 0.5 + 2.0 * (i/5).sin().abs(); });
* *

The final parameter, options, allows you to specify various optional arguments to * control the animation. They are:

* *

easing: The easing function name (from YAHOO.util.Easing) to control the * flow of the animation. Default is 'easeBoth'.

* *

after: A function to be called for each memeber of the collection when it finishes * its animation. The function receives the element and its position in the list as arguments.

* *

An example:

* *
   Ojay('#some-list li').animate({marginLeft: {to: 40}}, 5.0, {easing: 'elasticOut'});
* * @param {Object|Function} parameters * @param {Number|Function} duration * @param {Object} options * @returns {MethodChain} */ animate: function(parameters, duration, options) { var animation = new Ojay.Animation(this, parameters, duration, options); animation.run(); return animation.chain; }, /** * @param {Object} parameters * @param {Number|Function} duration * @param {Object} options * @returns {MethodChain} */ scroll: function(parameters, duration, options) { if (duration) { var animation = new Ojay.Animation(this, {scroll: {to: parameters}}, duration, options, YAHOO.util.Scroll); animation.run(); return animation.chain; } else { for (var i = 0, n = this.length; i < n; i++) { this[i].scrollLeft = parameters[0]; this[i].scrollTop = parameters[1]; } return this; } }, /** *

Adds the given string as a class name to all the elements in the collection and returns * a reference to the collection for chaining.

* @param {String} className * @returns {DomCollection} */ addClass: function(className) { Dom.addClass(this, className); this.trigger('ojay:classadded', {className: className}, false); return this; }, /** *

Removes the given class name(s) from all the elements in the collection and returns a * reference to the collection for chaining.

* @param {String} className * @returns {DomCollection} */ removeClass: function(className) { Dom.removeClass(this, className); this.trigger('ojay:classremoved', {className: className}, false); return this; }, /** *

Replaces oldClass with newClass for every element in the collection * and returns a reference to the collection for chaining.

* @param {String} oldClass * @param {String} newClass * @returns {DomCollection} */ replaceClass: function(oldClass, newClass) { Dom.replaceClass(this, oldClass, newClass); this.trigger('ojay:classremoved', {className: oldClass}, false); this.trigger('ojay:classadded', {className: newClass}, false); return this; }, /** *

Sets the class name of all the elements in the collection to the given value and * returns a reference to the collection for chaining.

* @param {String} className * @returns {DomCollection} */ setClass: function(className) { for (var i = 0, n = this.length; i < n; i++) this[i].className = className; this.trigger('ojay:classadded', {className: className}, false); return this; }, /** *

Returns true iff the first member of the collection has the given class name.

* @param {String} className * @returns {Boolean} */ hasClass: function(className) { if (!this.node) return undefined; return Dom.hasClass(this.node, className); }, /** *

Returns the value of the named style property for the first element in the collection.

* @param {String} name * @returns {String} */ getStyle: function(name) { if (!this.node) return undefined; return Dom.getStyle(this.node, String(name)); }, /** *

Sets the style of all the elements in the collection using a series of key/value pairs. * Keys correspond to CSS style property names, and should be camel-cased where they would * be hyphentated in stylesheets. Returns the DomCollection instance for chaining. * You need to use a string key for 'float' as it's a reserved word in JavaScript.

* *
    Ojay('p').setStyle({color: '#f00', fontSize: '14px', 'float': 'left'});
* * @param {Object} options * @returns {DomCollection} */ setStyle: function(options) { var value, isIE = !!YAHOO.env.ua.ie; for (var property in options) { if (isIE && property == 'opacity') { value = Number(options[property]); if (value === 0) options[property] = 0.001; if (value === 1) { Dom.setStyle(this, 'filter', ''); continue; } } Dom.setStyle(this, property, options[property]); } this.trigger('ojay:stylechange', {styles: options}, false); return this; }, /** *

Sets the given HTML attributes of all the elements in the collection, and returns the * collection for chaining. Use setClass() to change class names.

* *
    Ojay('img').set({src: 'images/tom.png'});
* *

Boolean attributes can be set and unset by passing in the appropriate boolean value.

* *
    Ojay('input[type=checkbox]').set({disabled: true});
* * @param {Object} options * @returns {DomCollection} */ set: function(options) { for (var i = 0, n = this.length; i < n; i++) { for (var key in options) { switch (options[key]) { case true: this[i].setAttribute(key, key); break; case false: this[i].removeAttribute(key); break; default: this[i].setAttribute(key, options[key]); } } } this.trigger('ojay:attrchange', {attributes: options}, false); return this; }, setAttributes: function() { return this.set.apply(this, arguments); }.traced('setAttributes() is deprecated; used set() instead', 'warn'), /** *

Hides every element in the collection and returns the collection.

* @returns {DomCollection} */ hide: function() { this.setStyle({display: 'none'}); this.trigger('ojay:hide', {}, false); return this; }, /** *

Shows/unhides every element in the collection and returns the collection.

* @returns {DomCollection} */ show: function() { this.setStyle({display: ''}); this.trigger('ojay:show', {}, false); return this; }, /** *

If html is a string, sets the innerHTML of every element in the * collection to the given string value. If html is an HTMLElement, inserts * the element into the first item in the collection (inserting DOM nodes multiple times just * moves them from place to place).

* @param {String|HTMLElement} html * @returns {DomCollection} */ setContent: function(html) { if (!this.node) return this; if (html instanceof this.klass) html = html.node; if (html && html.nodeType === Ojay.HTML.ELEMENT_NODE) { this.node.innerHTML = ''; this.node.appendChild(html); } else { this.forEach(function(element) { element.node.innerHTML = ''; element.insert(html, 'bottom'); }); } this.trigger('ojay:contentchange', {content: html}, true); return this; }, /** *

Inserts the given html (a String or an HTMLElement) into every * element in the collection at the given position. position can be one of * 'top', 'bottom', 'before' or 'after', and it defaults to * 'bottom'. Returns the DomCollection for chaining.

* *

If you supply an HTMLElement then it will only be inserted into the first element * of the collection; inserting an element multiple times simply moves it around the document. * If you want multiple insertions, you should clone the element yourself. Ojay does not clone it * for you as this removes event handlers you may have registered with the element.

* *
    Ojay('#someDiv').insert('<p>Inserted after the DIV</p>', 'after');
         *     
         *     Ojay('ul li').insert(Ojay.HTML.span({className: 'foo'}, 'Item: '), 'top');
* * @param {String|HTMLElement} html * @param {String} position * @returns {DomCollection} */ insert: function(html, position) { if (position == 'replace') return this.setContent(html); if (html instanceof this.klass) html = html.node; new Ojay.DomInsertion(this.toArray(), html, position); this.trigger('ojay:insert', {content: html, position: position}, true); return this; }, /** *

Removes all the elements in the collection from the document, and returns the collection.

* @returns {DomCollection} */ remove: function() { this.toArray().forEach(function(element) { if (element.parentNode) element.parentNode.removeChild(element); }); this.trigger('ojay:remove', {}, true); return this; }, /** *

Returns true iff the first element in the collection matches the given CSS selector.

* @param {String} selector * @returns {Boolean} */ matches: function(selector) { if (!this.node) return undefined; return Ojay.cssEngine.test(this.node, selector); }, /** *

Returns a new DomCollection containing the elements of the collection * that match the selector if one is given.

* @param {String} selector * @returns {DomCollection} */ query: function(selector, array) { var collection = array ? Ojay(array) : this; if (!selector) return new this.klass(collection.toArray()); collection = collection.filter({matches: selector}); return new this.klass(collection.toArray()); }, /** *

Returns a new DomCollection of the unique parent nodes of all the elements * in the collection. If a selector string is supplied, only elements that match the * selector are included.

* @param {String} selector * @returns {DomCollection} */ parents: function(selector) { var parents = this.toArray('parentNode'); return this.query(selector, parents.unique()); }, /** *

Returns a new DomCollection of the unique ancestor nodes of all the elements * in the collection. If a selector string is supplied, only elements that match the * selection are included.

* @param {String} selector * @returns {DomCollection} */ ancestors: function(selector) { var ancestors = []; this.toArray().forEach(function(element) { while ((element.tagName.toLowerCase() != 'body') && (element = element.parentNode)) { if (ancestors.indexOf(element) == -1) ancestors.push(element); } }); return this.query(selector, ancestors); }, /** *

Returns a new DomCollection of the unique child nodes of all the elements * in the collection. If a selector string is supplied, only elements that match the * selection are included.

* @param {String} selector * @returns {DomCollection} */ children: function(selector) { var children = []; this.toArray().forEach(function(element) { var additions = Dom.getChildren(element), arg; while (arg = additions.shift()) { if (children.indexOf(arg) == -1) children.push(arg); } }); return this.query(selector, children); }, /** *

Returns a new DomCollection of the unique descendant nodes of all the elements * in the collection. If a selector string is supplied, only elements that match the * selection are included.

* @param {String} selector * @returns {DomCollection} */ descendants: function(selector) { selector = selector || '*'; var descendants = []; this.toArray().forEach(function(element) { var additions = Ojay.cssEngine.query(selector, element), arg; while (arg = additions.shift()) { if (descendants.indexOf(arg) == -1) descendants.push(arg); } }); return new this.klass(descendants); }, /** *

Returns a new DomCollection of the unique siblings of all the elements in the * collection. The returned collection does not include elements present in the original * collection. If a selector string is supplied, only elements that match the selection are * included.

* @param {String} selector * @returns {DomCollection} */ siblings: function(selector) { var these = this.toArray(), siblings = []; these.forEach(function(element) { var additions = Ojay(element).parents().children(selector).toArray(), arg; while (arg = additions.shift()) { if ((these.indexOf(arg) == -1) && (siblings.indexOf(arg) == -1)) siblings.push(arg); } }); return new this.klass(siblings); }, /** *

Returns a Region object representing the rectangle occupied by the the first * element in the collection.

* @returns {Region} */ getRegion: function() { if (!this.node) return undefined; return new Ojay.Region(Dom.getRegion(this.node)); }, /** *

Resizes every member of the collection so as to fit inside the given region exactly.

* @param {Region} region * @returns {DomCollection} */ fitToRegion: function(region) { var width = region.getWidth(), height = region.getHeight(); this.forEach(function(element) { element.setStyle({width: width + 'px', height: height + 'px'}); var reg = element.getRegion(), w = reg.getWidth(), h = reg.getHeight(); element.setStyle({width: (2 * width - w) + 'px', height: (2 * height - h) + 'px'}); }); this.trigger('ojay:regionfit', {}, false); return this; }, /** *

Returns the total width of the region occupied by the element, including padding * and borders. Values returned are in pixels.

* @returns {Number} */ getWidth: function() { if (!this.node) return undefined; return this.getRegion().getWidth(); }, /** *

Returns the total height of the region occupied by the element, including padding * and borders. Values returned are in pixels.

* @returns {Number} */ getHeight: function() { if (!this.node) return undefined; return this.getRegion().getHeight(); }, /** *

Returns the position of the top edge of the first element in the collection relative * to the viewport, in pixels.

* @returns {Number} */ getTop: function() { if (!this.node) return undefined; return this.getRegion().top; }, /** *

Returns the position of the bottom edge of the first element in the collection relative * to the viewport, in pixels.

* @returns {Number} */ getBottom: function() { if (!this.node) return undefined; return this.getRegion().bottom; }, /** *

Returns the position of the left edge of the first element in the collection relative * to the viewport, in pixels.

* @returns {Number} */ getLeft: function() { if (!this.node) return undefined; return this.getRegion().left; }, /** *

Returns the position of the right edge of the first element in the collection relative * to the viewport, in pixels.

* @returns {Number} */ getRight: function() { if (!this.node) return undefined; return this.getRegion().right; }, /** *

Returns the position of the center of the element as an object with left and * top properties. Values returned are in pixels.

* @returns {Object} */ getCenter: function() { if (!this.node) return undefined; return this.getRegion().getCenter(); }, /** *

Returns true iff the first element in the collection intersects the area of the element * given as an argument.

* @param {String|HTMLElement|DomCollection} element * @returns {Boolean} */ areaIntersects: function(element) { if (!this.node) return undefined; var node = Ojay(element); return this.getRegion().intersects(node.getRegion()); }, /** *

Returns a Region representing the overlapping region of the first element in the * collection and the argument.

* @param {String|HTMLElement|DomCollection} element * @returns {Region} */ intersection: function(element) { if (!this.node) return undefined; var node = Ojay(element); var A = this.getRegion(), B = node.getRegion(); return A.intersects(B) ? A.intersection(B) : null; }, /** *

Returns true iff the first element in the collection completely contains the area of the * element given as an argument.

* @param {String|HTMLElement|DomCollection} element * @returns {Boolean} */ areaContains: function(element) { if (!this.node) return undefined; var node = Ojay(element); return this.getRegion().contains(node.getRegion()); } }); })(Ojay, YAHOO.util.Dom); (function() { var methods = {}; for (var method in Ojay.ARRAY_METHODS) (function(name) { var noConvert = /^(?:indexOf|lastIndexOf|unique)$/.test(name); methods[name] = function() { var array = noConvert ? this.toArray() : this.toArray(Ojay); var result = array[name].apply(array, arguments); if (name == 'filter') result = Ojay(result.map(function(el) { return el.node; })); return result; }; })(method); Ojay.DomCollection.include(methods); })(); Ojay.fn = Ojay.DomCollection.prototype; /** *

The DomInsertion class is used to insert new strings and elements into the DOM. * It should not be used as a public API; you should use DomCollection's insert * method instead. Its implementation is based on that * used by Prototype.

* * Document insertion code: Copyright (c) 2005-2008 Sam Stephenson / the Prototype team, * released under an MIT-style license. * * @contructor * @class DomInsertion */ Ojay.DomInsertion = new JS.Class('Ojay.DomInsertion', /** @scope Ojay.DomInsertion.prototype */{ /** * @param {Array|HTMLElement} elements * @param {String|HTMLElement} html * @param {String} position */ initialize: function(elements, html, position) { if (!(elements instanceof Array)) elements = [elements]; if (!(/^(?:top|bottom|before|after)$/i.test(position))) position = 'bottom'; this._elements = elements.filter(function(el) { return el && el.nodeType === Ojay.HTML.ELEMENT_NODE; }); this._html = html; this._position = position.toLowerCase(); if (this._elements.length === 0) return; if (this._html && this._html.nodeType) this._insertElement(); if (typeof this._html == 'string') this._insertString(); }, /** *

Performs insertion of HTMLElements.

*/ _insertElement: function() { var insert = this.klass._TRANSLATIONS[this._position]; this._elements.forEach(function(element) { insert(element, this._html); }, this); }, /** *

Performs insertion of Strings.

*/ _insertString: function() { var insert = this.klass._TRANSLATIONS[this._position]; this._elements.forEach(function(element) { var tagName = (/^(?:before|after)$/.test(this._position) ? element.parentNode : element).tagName.toUpperCase(); var childNodes = this._getContentFromElement(tagName); if (/^(?:top|after)$/.test(this._position)) childNodes.reverse(); childNodes.forEach(insert.partial(element)); }, this); }, /** *

Returns a collection of nodes by creating a new DIV and using innerHTML * to create the elements. Used when inserting into table elements and SELECT boxes, * which don't allow innerHTMLmodifications quite like everything else.

* @param {String} tagName * @returns {Array} */ _getContentFromElement: function(tagName) { var tag = this.klass._TAGS[tagName]; var div = Ojay.HTML.div(); if (tag) { div.innerHTML = tag[0] + this._html + tag[1]; for (var i = 0, n = tag[2]; i < n; i++) div = div.firstChild; } else div.innerHTML = this._html; return Array.from(div.childNodes); }, extend: /** @scope Ojay.DomInsertion */{ /** *

Collection of definitions for how to perform insertions of strings and elements at * various positions.

*/ _TRANSLATIONS: { top: function(element, html) { element.insertBefore(html, element.firstChild); }, bottom: function(element, html) { element.appendChild(html); }, before: function(element, html) { element.parentNode.insertBefore(html, element); }, after: function(element, html) { element.parentNode.insertBefore(html, element.nextSibling); } }, /** *

Tags that need special treatment when trying to use innerHTML.

*/ _TAGS: { TABLE: ['', '
', 1], THEAD: ['', '
', 2], TBODY: ['', '
', 2], TFOOT: ['', '
', 2], TR: ['', '
', 3], TD: ['
', '
', 4], TH: ['
', '
', 4], SELECT: ['', 1] } } }); /** *

Sane DOM node creation API, inspired by * Builder::XmlMarkup * in Ruby on Rails.

* *

This class lets you use a much nicer syntax for creating DOM nodes, without resorting to * document.createElement and friends. Essentially, you write JavaScript that mirrors * the HTML you're creating. The methods in the class return HTMLElement objects rather * than strings of HTML.

* *

To begin, you create a new HtmlBuilder:

* *
    var html = new Ojay.HtmlBuilder();
* *

Then write your HTML. Use hashes for tag attributes, strings for text nodes, and functions * to nest further tags inside the current node. The beauty of this is that you can easily add * whatever logic you want inside the functions to customize the HTML generated. A simple example:

* *
    var div = html.div({id: 'container'}, function(html) {
 *         html.h1('This is the title');
 *         html.p({className: 'para'}, 'Lorem ipsum dolor sit amet...');
 *         html.ul(function(html) {
 *             ['One', 'Two', 'Three'].forEach(html.method('li'));
 *         });
 *     });
* *

Now div is an HTMLElement object with the following structure:

* *
    <div id="container">
 *         <h1>This is the title</h1>
 *         <p class="para">Lorem ipsum dolor sit amet...</p>
 *         <ul>
 *             <li>One</li>
 *             <li>Two</li>
 *             <li>Three</li>
 *         </ul>
 *     </div>
* *

If you prefer, there is a pre-initialized instance of HtmlBuilder named * Ojay.HTML. So, you can call Ojay.HTML.div('DIV content') and the like.

* *

One key advantage of writing HTML out using JavaScript is that you can assign references * to elements as they are being created, without needing to add IDs or class names to them for * later reference. For example:

* *
    var FormController = new JS.Class({
 *         
 *         initialize: function(element) {
 *             element = Ojay(element);
 *             var self = this;
 *             var form = Ojay.HTML.form(function(html) {
 *                 html.h3('Enter your email address');
 *                 html.label('Email:');
 *                 self.emailField = html.input({type: 'text'});
 *                 self.button = html.input({type: 'submit', value: 'Go!'});
 *             });
 *             this.form = Ojay(form);
 *             element.setContent(form);
 *             this.registerEventHandlers();
 *         },
 *         
 *         registerEventHandlers: function() {
 *             this.form.on('submit', function(e) {
 *                 alert(this.emailField.value);
 *             }, this);
 *         }
 *     });
* *

Note how the emailField property is set at the same time that the element is * being created. Storing this reference means you don't have to crawl the DOM for the right * node later on, so performance is improved. Also, the fact that you don't need to add IDs * or class names to the new elements means you've less chance of causing a naming collision * with existing page elements, or unintentionally inheriting stylesheet rules.

* *

All the tags defined in the HTML 4.01 spec are available in HtmlBuilder. You can * see which tags are implemented by inspecting the array Ojay.HtmlBuilder.TAG_NAMES.

* * @constructor * @class HtmlBuilder */ Ojay.HtmlBuilder = new JS.Class('Ojay.HtmlBuilder', /* @scope Ojay.HtmlBuilder.prototype */{ /** * @param {HTMLElement} node */ initialize: function(node) { this._rootNode = node || null; }, /** * @param {HTMLElement} node */ concat: function(node) { if (this._rootNode) this._rootNode.appendChild(node); return node; }, extend: { addTagNames: function() { var args = (arguments[0] instanceof Array) ? arguments[0] : arguments; for (var i = 0, n = args.length; i < n; i++) this.addTagName(args[i]); }, addTagName: function(name) { this.define(name, function() { var node = document.createElement(name), arg, attr, style, appendable, type = (arguments[0]||{}).type || 'text'; if (YAHOO.env.ua.ie && name == 'input') node = document.createElement(''); loop: for (var j = 0, m = arguments.length; j < m; j++) { arg = arguments[j]; switch (typeof arg) { case 'object': appendable = arg.node || arg; if (appendable.nodeType === Ojay.HTML.ELEMENT_NODE) { node.appendChild(appendable); } else { for (attr in arg) { if (Number(attr) == attr) continue; if (attr == 'style') for (style in arg[attr]) node.style[style] = arg[attr][style]; else node[attr] = arg[attr]; } } break; case 'function': arg(new Ojay.HtmlBuilder(node)); break; case 'string': node.appendChild(document.createTextNode(arg)); break; } } if (this._rootNode) this._rootNode.appendChild(node); return node; }); }, /** * List of all HTML 4.01 tag names, culled from the W3C spec. */ TAG_NAMES: ( "a abbr acronym address applet area b base basefont bdo big blockquote body " + "br button caption center cite code col colgroup dd del dfn dir div dl dt em " + "embed fieldset font form frame frameset h1 h2 h3 h4 h5 h6 head hr html i " + "iframe img input ins isindex kbd label legend li link map menu meta noframes " + "noscript object ol optgroup option p param pre q s samp script select small " + "span strike strong style sub sup table tbody td textarea tfoot th thead title " + "tr tt u ul var" ).split(/\s+/) } }); Ojay.HtmlBuilder.addTagNames(Ojay.HtmlBuilder.TAG_NAMES); /** *

A pre-initialized instance of HtmlBuilder.

*/ Ojay.HTML = new Ojay.HtmlBuilder(); /** *

Named references to all types of DOM node -- these are defined in Mozilla but not in IE.

*/ JS.extend(Ojay.HTML, /** @scope Ojay.HTML */{ 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 }); /** * @overview *

The Animation class is used to set up all animations in Ojay. It is entirely * for internal consumption, and not to be accessed directly. Use the animate method * in DomCollection instead, and look to that for documentation.

* @constructor * @class Animation */ Ojay.Animation = new JS.Class('Ojay.Animation', /** @scope Ojay.Animation.prototype */{ extend: /** @scope Ojay.Animation */{ DEFAULT_YUI_CLASS: YAHOO.util.ColorAnim }, /** * @param {DomCollection} elements * @param {Object|Function} parameters * @param {Number|Function} duration * @param {Object} options * @param {klass} animationClass */ initialize: function(elements, parameters, duration, options, animationClass) { this._collection = elements; this._parameters = parameters || {}; this._duration = duration || 1.0; this._options = options || {}; this._animClass = animationClass || this.klass.DEFAULT_YUI_CLASS; this._easing = YAHOO.util.Easing[this._options.easing || 'easeBoth']; var after = this._options.after, before = this._options.before; this._afterCallback = after && Function.from(after); this._beforeCallback = before && Function.from(before); this.chain = new JS.MethodChain; }, /** * @param {Object|Function} options * @param {DomCollection} element * @param {Number} i * @returns {Object} */ _evaluateOptions: function(options, element, i) { if (typeof options == 'function') options = options(i, element); if ((options instanceof Array) || (typeof options != 'object')) return options; var results = {}; for (var field in options) results[field] = arguments.callee(options[field], element, i); return results; }.curry(), /** *

Runs the animation.

*/ run: function() { var paramSets = this._collection.map(this._evaluateOptions(this._parameters)); var durations = this._collection.map(this._evaluateOptions(this._duration)); var maxDuration = durations.reduce(function(a,b) { return a > b ? a : b; }, -Infinity); var callbackAttached = false; var after = this._afterCallback, before = this._beforeCallback; this._collection.trigger('ojay:animstart', {}, false); this._collection.forEach(function(element, i) { var parameters = paramSets[i], duration = durations[i]; var anim = new this._animClass(element.node, parameters, duration, this._easing); anim.onComplete.subscribe(function() { if (YAHOO.env.ua.ie && (parameters.opacity || {}).to !== undefined) element.setStyle({opacity: parameters.opacity.to}); element.trigger('ojay:animend', {}, false); if (after) after(element, i); if (duration == maxDuration && !callbackAttached) { callbackAttached = true; this.chain.fire(this._collection); } }.bind(this)); if (before) before(element, i); anim.animate(); }, this); } }); (function(Region) { /** *

The Region class wraps YUI's Region class and extends its API. This * class is mostly for internal consumption: methods should exist on DomCollection * for getting the geometric properties of DOM elements.

* @constructor * @class Region */ Ojay.Region = new JS.Class('Ojay.Region', /** @scope Ojay.Region.prototype */{ contains: Region.prototype.contains, getArea: Region.prototype.getArea, _intersect: Region.prototype.intersect, _union: Region.prototype.union, /** * @param {YAHOO.util.Region} region */ initialize: function(region) { ['top', 'right', 'bottom', 'left'].forEach(function(property) { this[property] = region[property] || 0; }, this); }, /** * @returns {Number} */ getWidth: function() { return this.right - this.left; }, /** * @returns {Number} */ getHeight: function() { return this.bottom - this.top; }, /** * @returns {Number} */ getDiagonal: function() { return (this.getWidth().pow(2) + this.getHeight().pow(2)).sqrt(); }, /** * @returns {Object} */ getCenter: function() { return { left: (this.left + this.right) / 2, top: (this.top + this.bottom) / 2 }; }, /** * @param {Number} x * @param {Number} y * @returns {Region} */ shift: function(x,y) { this.left += x; this.right += x; this.top += y; this.bottom += y; return this; }, /** * @param {Number} factor * @returns {Region} */ scale: function(factor) { var w = this.getWidth(), h = this.getHeight(); if (w <= 0 || h <= 0) return this; var dx = (factor - 1) * w, dy = (factor - 1) * h; this.left -= dx/2; this.right += dx/2; this.top -= dy/2; this.bottom += dy/2; return this; }, /** * @param {Number} left * @param {Number} top * @returns {Region} */ centerOn: function(left, top) { var myCenter = this.getCenter(), theirCenter; if (typeof left == 'object') { theirCenter = left.getCenter(); left = theirCenter.left; top = theirCenter.top; } this.shift(left - myCenter.left, top - myCenter.top); return this; }, /** * @param {Region} region * @returns {Region} */ intersection: function(region) { var intersection = this._intersect(region); return new Ojay.Region(intersection); }, /** *

Returns true iff this region intersects the given region.

* @param {Region} region * @returns {Boolean} */ intersects: function(region) { var top = Math.max(this.top, region.top), bottom = Math.min(this.bottom, region.bottom), left = Math.max(this.left, region.left), right = Math.min(this.right, region.right); return (top < bottom) && (left < right); }, /** * @param {Region} region * @returns {Region} */ union: function(region) { var union = this._union(region); return new Ojay.Region(union); }, /** * @returns {String} */ toString: function() { return '(' + this.left + ',' + this.top + ') [' + this.getWidth() + 'x' + this.getHeight() + ']'; }, extend: /** @scope Ojay.Region */{ convert: function(object) { if (object instanceof Region) return new this(object); if (!(object instanceof this)) object = Ojay(object).getRegion(); if (!object) return undefined; else return object; } } }); })(YAHOO.util.Region); /** *

The Sequence class allows iteration over an array using a timer to * skip from member to member. At each timeframe, the sequence object calls a user- * defined callback function, passing in the current member (the 'needle') and its * position in the list.

* @constructor * @class Ojay.Sequence */ Ojay.Sequence = new JS.Class('Ojay.Sequence', /** @scope Ojay.Sequence.prototype */{ /** * @param {Array} list * @param {Function} callback * @param {Object} context */ initialize: function(list, callback, context) { this._list = list; this._counter = 0; this._callback = Function.from(callback); this._context = context || null; this._interval = null; this._looping = false; this._pauseOnComplete = false; }, _fireCallback: function() { this._callback.call(this._context, this._list[this._counter]); }, /** *

Calls the callback function on the current needle and steps the counter forward by * one place. When looping, sets a timeout to call itself again after the specified time.

* @returns {Sequence} */ stepForward: function() { if (this._looping === null) { this._looping = false; return this; } this._fireCallback(); this._counter++; if (this._counter >= this._list.length) { this._counter = 0; if (this._pauseOnComplete) this._looping = this._pauseOnComplete = false; } if (this._looping) setTimeout(this.method('stepForward'), this._interval); return this; }, /** *

Makes the sequence step forward indefinately at timed intervals.

* @param {Number} time * @returns {Sequence} */ loop: function(time) { this._interval = 1000 * Number(time || 0) || this._interval; if (!this._interval || this._looping) return this; this._looping = true; return this.stepForward(); }, /** *

Stops the sequence looping. The needle will be placed after the last called-back needle.

* @returns {Sequence} */ pause: function() { if (this._looping) this._looping = null; return this; }, /** *

Causes the sequence to stop looping when it reaches the end of the list.

* @returns {Sequence} */ finish: function() { if (this._looping) this._pauseOnComplete = true; return this; } }); /** *

Returns a Sequence object that cycles over every member of the array over * the given time interval. Your callback function is called every time * seconds, being passed each member of the array in turn and its position in the list.

* *
    // Cycle over a set of images
 *     var imgs = ['/imgs/one.png', 'imgs/two.png', 'imgs/three.png'];
 *     var element = Ojay('#something');
 *     
 *     var sequence = imgs.sequence(function(imgageSource, i) {
 *         element.set({src: imageSource});
 *     });
 *     
 *     // Start sequence looping with a time period
 *     sequence.loop(5);
 *     
 *     // Pause the sequence
 *     sequence.pause();
 *     
 *     // Start again where we left off
 *     sequence.loop();
 *     
 *     // Stop when it next gets to the end of the list
 *     sequence.finish();
* * @param {Number} time * @param {Function} callback * @returns {Sequence} */ Array.prototype.sequence = function(callback) { return new Ojay.Sequence(this, callback); }; Ojay.DomCollection.include(/** @scope Ojay.DomCollection.prototype */{ /** *

Returns a Sequence operating on the members of the collection. * See Array#sequence for more information.

* @param {Number} time * @param {Function} callback * @returns {Sequence} */ sequence: function(callback) { return [].map.call(this, function(el) { return Ojay(el); }) .sequence(callback); } }); JS.MethodChain.addMethods(Ojay); (function() { // ObjectMethods will be renamed to Kernel in JS.Class 2.1 var kernel = JS.ObjectMethods || JS.Kernel; var convertSelectors = function() { var args = Array.from(arguments), _ = args.shift(); if (typeof args[0] == 'string') return _(Ojay, args[0]); else return _.apply(this, args); }; // Modify MethodChain to allow CSS selectors JS.MethodChain.prototype._ = JS.MethodChain.prototype._.wrap(convertSelectors); kernel.include({ _: kernel.instanceMethod('_').wrap(convertSelectors) }); })();_application/x-javascriptO*bplist00z{X$versionX$objectsY$archiverT$top("()0!12TUVWXYZ[\]^_`abcdefghijklmnoptuU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1&'#$%&[NS.relativeWNS.base_-https://cdn.othermedia.com/ojay/0.4.1/core.js*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#ADڭ 3456EWNS.keysZNS.objects%789:;<=>?@ABCD FGHIJKLMNOPQRS !"#$VServerZConnectionZKeep-Alive_Content-EncodingTVary\Content-TypeWExpires]Cache-Control]Accept-Ranges_X-Ua-Compatible]Last-ModifiedWX-CacheTDate^Content-LengthVApacheZKeep-Alive_timeout=2, max=100Tgzip_Accept-Encoding,U_application/x-javascript_Fri, 08 Oct 2021 17:18:04 GMT_max-age=315360000Ubytes]IE=EmulateIE7_Thu, 25 Jun 2009 14:45:23 GMT_MISS from cdn.othermedia.com_Tue, 11 Oct 2011 17:18:04 GMTU23086*+qr_NSMutableDictionaryqs/\NSDictionary#*+vw_NSHTTPURLResponsexy/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiver|}_WebResourceResponse#-27bh)28;AJSU\doq -?MUZip{ ,Kkqv ~_-https://cdn.othermedia.com/ojay/0.4.1/core.jswxyzO/* Copyright (c) 2007-2008 the OTHER media Limited Licensed under the BSD license, http://ojay.othermedia.org/license.html Version: 0.4.1 Build: source */ (function(Ojay) { /** *

Returns a function that performs the given method while an overlay is hidden. Use * this to generate methods that require the overlay to be visible that can be run while * keeping an overlay hidden. The generated method will briefly show the overlay in order * to perform the method before hiding it again, and you should not see the overlay appear * in most situations.

* @private * @param {String} method * @returns {Function} */ var whileHidden = function(method) { return function() { var container = this._elements._container; container.setStyle({visibility: 'hidden'}); this.show('none', {silent: true})[method]().hide('none', {silent: true}); container.setStyle({visibility: ''}); return this; }; }; /** *

The Overlay class is used to encapsulate the process of positioning a * container element on top of the rest of the document and allowing it to be positioned * and sized to order. The class provides a number of transition effects for showing and * hiding overlay elements, which you can use if you include YAHOO.util.Anim in * your pages.

* *

This class is unlikely to be directly useful to you in building pages, but it provides * a base class that other overlay types inherit from. It provides all the positioning, * sizing, layering, showing and hiding functionality useful for implementing any kind of * overlay behaviour. The set of classes implemented by Ojay is:

* *
 *                          ===============
 *                          ||  Overlay  ||
 *                          ===============
 *                                 |
 *                    --------------------------
 *                    |                        |
 *          ======================      ================
 *          ||  ContentOverlay  ||      ||  PageMask  ||
 *          ======================      ================
 *                    |
 *             ===============
 *             ||  Tooltip  ||
 *             ===============
 * 
* *

To create an overlay, simply call its contructor with a set of initialization options. * These options include (all sizing and position is in pixels):

* *
    *
  • left: the initial left position
  • *
  • top: the initial top position
  • *
  • width: the initial element width
  • *
  • height: the initial element height
  • *
  • layer: the initial layer (z-index)
  • *
  • opacity: the initial opacity (between 0 and 1 inclusive)
  • *
  • className: space-separated list of classes to give to the overlay element
  • *
* *

All these options are optional - you can omit any of them and default values will be * applied. An example creation might look like:

* *
    var overlay = new Ojay.Overlay({
 *         width:  600,
 *         height: 300,
 *         className: 'my-overlay panel'
 *     });
* *

Which would insert the following elements at the top of the body element:

* *
    <div class="overlay-container my-overlay panel"></div>
* *

This new div will be absolutely positioned and sized according to the setup * options you specified. You can get a reference to it by calling overlay.getContainer():

* *
    overlay.getContainer().on('click', function() { ... });
* *

See the method definitions in the class below for further API documentation.

* * @constructor * @class Overlay */ Ojay.Overlay = new JS.Class('Ojay.Overlay', /** @scope Ojay.Overlay.prototype */{ include: [JS.State, Ojay.Observable], extend: /** @scope Ojay.Overlay */{ BASE_LAYER: 1000, MINIMUM_OFFSET: 20, DEFAULT_SIZE: {width: 400, height: 300}, DEFAULT_POSITION: {left: 50, top: 50}, DEFAULT_OPACITY: 1, CONTAINER_CLASS: 'overlay-container', TRANSITION_TIME: 0.4, EASING: 'easeOutStrong', /** *

The Overlay.Transitions object stores transition effects used to hide and * show overlay instances. This allows new effects to be added without needing to modify * Overlay source code. To register new transitions, you need to implement a * show() and a hide() method, each of which must accept an Overlay * object and a MethodChain to allow code to be asynchronously chained after * the effect has run. You must decide when to fire the chain, and your methods must * return either the chain or the overlay. You will usually return the chain if your * transition involves animation. The basic pattern is thus:

* *
    Ojay.Overlay.Transitions.add('myeffect', {
         *         show: function(overlay, chain) {
         *             // ...
         *             return chain;
         *         },
         *         hide: function(overlay, chain) {
         *             // ...
         *             return chain;
         *         }
         *     });
* *

You will then be able to use this effect to show and hide overlays:

* *
    overlay.show('myeffect');
* *

See the transitions that ship with Ojay for some example implementations.

* * @class Overlay.Transitions */ Transitions: new JS.Singleton('Ojay.Overlay.Transitions', /** @scope Ojay.Overlay.Transitions */{ _store: {}, /** *

The interface used to test registered transitions.

*/ INTERFACE: new JS.Interface(['hide', 'show']), /** *

A stub transition returned if none can be found for a given name.

*/ _stub: { hide: function(overlay) { return overlay; }, show: function(overlay) { return overlay; } }, /** *

Adds a new transition object to the set of registered transitions.

* @param {String} name * @param {Object} transitions Must implement Ojay.Overlay.Transitions.INTERFACE * @returns {Transitions} */ add: function(name, transitions) { JS.Interface.ensure(transitions, this.INTERFACE); this._store[name] = transitions; return this; }, /** *

Returns the transition object with the given name.

* @param {String} name * @returns {Object} Implements Ojay.Overlay.Transitions.INTERFACE */ get: function(name) { return this._store[name] || this._stub; } }), /** *

Returns the layer (z-index) of the given object. Can accept Overlay * objects and HTMLElement/DomCollection objects, and anything * with a getLayer() method.

* @param {Object} object * @returns {Number} */ getLayer: function(object) { if (object.getLayer) return Number(object.getLayer()); if (object.nodeType == Ojay.HTML.ELEMENT_NODE || typeof object == 'string') object = Ojay(object); if (object.getStyle) return Number(object.getStyle('zIndex')) || 0; return 0; } }, /** * @param {Object} options */ initialize: function(options) { this._elements = {}; options = this._options = options || {}; Ojay(document.body).insert(this.getHTML().node, 'top'); this.setState('INVISIBLE'); this.setSize(options.width, options.height); this.setPosition(options.left, options.top); this.setLayer(options.layer); this.setOpacity(options.opacity); }, /** * Returns a DomCollection wrapping the HTML elements for the overlay.

* @returns {DomCollection} */ getHTML: function() { var self = this, elements = self._elements; if (elements._container) return elements._container; var container = Ojay( Ojay.HTML.div({className: this.klass.CONTAINER_CLASS}) ); container.setStyle({position: 'absolute', overflow: 'hidden'}).hide(); container.setStyle({padding: '0 0 0 0', border: 'none'}); (this._options.className || '').trim().split(/\s+/).forEach(container.method('addClass')); return elements._container = container; }, /** *

Returns a DomCollection wrapping the overlay's container element. * Effectively an alias for getHTML().

* @returns {DomCollection} */ getContainer: function() { return this._elements._container; }, /** *

Sets the position of the overlay, measured in pixels from the top-left corner * of the document. Positioning is absolute rather than fixed.

* @param {Number|String} left * @param {Number|String} top * @returns {Overlay} */ setPosition: function(left, top) { if (this.inState('CLOSED')) return this; var defaults = this.klass.DEFAULT_POSITION; left = this._addUnits(left === undefined ? defaults.left : left); top = this._addUnits(top === undefined ? defaults.top : top); this._position = {left: left, top: top}; if (this.inState('VISIBLE')) this._elements._container.setStyle(this._position); return this; }, /** *

Returns the current position of the overlay as an object with left and * top fields. If the strings flag is passed true, the positions * are returned as strings containing units, otherwise they are returned as numbers with * the units implcitly being pixels.

* @param {Boolean} strings * @returns {Object} */ getPosition: function(strings) { var pos = this._position, left = pos.left, top = pos.top; return strings ? {left: left, top: top} : {left: parseInt(left), top: parseInt(top)}; }, /** *

Sets the size of the overlay element in pixels. You may also use strings to specify * the dimensions if you want to use units other than pixels, e.g. '67em'.

* @param {Number|String} width * @param {Number|String} height * @returns {Overlay} */ setSize: function(width, height) { if (this.inState('CLOSED')) return this; var defaults = this.klass.DEFAULT_SIZE; width = this._addUnits(width === undefined ? defaults.width : width); height = this._addUnits(height === undefined ? defaults.height : height); this._dimensions = {width: width, height: height}; if (this.inState('VISIBLE')) this._elements._container.setStyle(this._dimensions); return this; }, /** *

Returns the current size of the overlay as an object with width and * height fields. If the strings flag is passed true, the dimensions * are returned as strings containing units, otherwise they are returned as numbers with * the units implcitly being pixels.

* @param {Boolean} strings * @returns {Object} */ getSize: function(strings) { var size = this._dimensions, width = size.width, height = size.height; return strings ? {width: width, height: height} : {width: parseInt(width), height: parseInt(height)}; }, /** *

Returns an Ojay.Region instance representing the area occupied by the overlay.

* @returns {Region} */ getRegion: function() { return !this.inState('INVISIBLE', 'CLOSED') ? this._elements._container.getRegion() : undefined; }, /** *

Sets the opacity of the overlay as a number from 0 to 1 inclusive.

* @param {Number} opacity * @returns {PageMask} */ setOpacity: function(opacity) { this._opacity = (opacity === undefined) ? this.klass.DEFAULT_OPACITY : Number(opacity); if (this._opacity > 1) this._opacity /= 100; if (this.inState('VISIBLE')) this._elements._container.setStyle({opacity: this._opacity}); return this; }, /** *

Returns the current opacity of the overlay, a number between 0 and 1 inclusive.

* @returns {Number} */ getOpacity: function() { return this._opacity; }, /** *

Positions the receiving overlay behind the passed parameter by setting the receiving * overlay's z-index.

* @param {Overlay} overlay * @returns {Overlay} */ positionBehind: function(overlay) { return this.setLayer(this.klass.getLayer(overlay) - 1); }, /** *

Positions the receiving overlay in front of the passed parameter by setting the receiving * overlay's z-index.

* @param {Overlay} overlay * @returns {Overlay} */ positionInFront: function(overlay) { return this.setLayer(this.klass.getLayer(overlay) + 1); }, /** *

Sets the layer (z-index) of the overlay to the given value.

* @param {Number} index * @returns {Overlay} */ setLayer: function(index) { if (this.inState('CLOSED')) return this; this._layer = (index === undefined) ? this.klass.BASE_LAYER : Number(index); this._elements._container.setStyle({zIndex: this._layer}); return this; }, /** *

Returns the current layer (z-index) of the overlay.

* @returns {Number} */ getLayer: function() { return this._layer; }, states: /** @scope Ojay.Overlay.prototype */{ /** *

An overlay is in the INVISIBLE state when it is present in the document * but is not visible.

*/ INVISIBLE: /** @scope Ojay.Overlay.prototype */{ /** *

Centers the overlay within the viewport.

* @returns {Overlay} */ center: whileHidden('center'), /** *

Shows the overlay using the given transition. Returns a MethodChain * object so you can chain code to run after the transition finishes. The root of * this chain is the receiving overlay instance.

* @param {String} transition * @param {Object} options * @returns {Overlay|MethodChain} */ show: function(transition, options) { this.setState('SHOWING'); transition = this.klass.Transitions.get(transition || 'none'); var chain = new JS.MethodChain()._(this).setState('VISIBLE'); if ((options||{}).silent !== true) chain._(this).notifyObservers('show'); chain._(this); return transition.show(this, chain); }, /** *

'Closes' the overlay by removing it from the document.

* @param {Object} options * @returns {Overlay} */ close: function(options) { this._elements._container.remove(); this.setState('CLOSED'); if ((options||{}).silent !== true) this.notifyObservers('close'); return this; } }, /** *

An overlay is in the SHOWING state when it is transitioning between * INVISIBLE and VISIBLE.

*/ SHOWING: /** @scope Ojay.Overlay.prototype */{}, /** *

An overlay is in the VISIBLE state when it is present in the document * and visible.

*/ VISIBLE: /** @scope Ojay.Overlay.prototype */{ /** *

Centers the overlay within the viewport.

* @returns {Overlay} */ center: function() { var region = this.getRegion(), screen = Ojay.getVisibleRegion(), left = screen.left + (screen.getWidth() - region.getWidth()) / 2, top = screen.top + (screen.getHeight() - region.getHeight()) / 2; if (left < this.klass.MINIMUM_OFFSET) left = this.klass.MINIMUM_OFFSET; if (top < this.klass.MINIMUM_OFFSET) top = this.klass.MINIMUM_OFFSET; return this.setPosition(left, top); }, /** *

Hides the overlay using the named transition. Does not remove the overlay from * the document. Returns a MethodChain that will fire on the receiving * overlay instance on completion of the transition effect.

* @param {String} transition * @param {Object} options * @returns {Overlay|MethodChain} */ hide: function(transition, options) { this.setState('HIDING'); transition = this.klass.Transitions.get(transition || 'none'); var chain = new JS.MethodChain()._(this).setState('INVISIBLE'); if((options||{}).silent !== true) chain._(this).notifyObservers('hide'); chain._(this); return transition.hide(this, chain); }, /** *

Closes the overlay by hiding it using the named transition and removing it * from the document. Returns a MethodChain that will fire on the receiving * overlay instance on completion of the transition effect.

* @param {String} transition * @param {Object} options * @returns {MethodChain} */ close: function(transition, options) { return this.hide(transition, options)._(this).close(options); }, /** *

Resizes the overlay using an animation that can be controlled via an options * hash. You can specify the area to resize to using left, top, width, height params * individually, or using a region object. The method returns a MethodChain * that will fire on the receiving overlay once the animation has finished.

* *

Some examples:

* * overlay.resize(50, 80, 100, 500); * *
    overlay.resize(Ojay.getVisibleRegion(), {
             *         duration:   4,
             *         easing:     'easeBoth'
             *     });
* * @param {Number} left * @param {Number} top * @param {Number} width * @param {Number} height * @param {Object} options * @returns {MethodChain} */ resize: function(left, top, width, height, options) { var region = left, options = options || {}; if (typeof region == 'object') { options = top || {}; left = region.left; top = region.top; width = region.getWidth(); height = region.getHeight(); } this.setState('RESIZING'); return this._elements._container.animate({ left: {to: left}, top: {to: top}, width: {to: width}, height: {to: height} }, options.duration || this.klass.TRANSITION_TIME, {easing: options.easing || this.klass.EASING}) ._(this).setSize(width, height) ._(this).setPosition(left, top) ._(this).setState('VISIBLE')._(this); } }, /** *

An overlay is in the HIDING state when it is transitioning between * VISIBLE and INVISIBLE.

*/ HIDING: /** @scope Ojay.Overlay.prototype */{}, /** *

An overlay is in the RESIZING state when it is in the process of being resized.

*/ RESIZING: /** @scope Ojay.Overlay.prototype */{}, /** *

An overlay is in the CLOSED state when it has been removed from the document. * No further work can be done with the overlay once it is in this state.

*/ CLOSED: /** @scope Ojay.Overlay.prototype */{} }, _addUnits: function(x) { return String(x).replace(/^(-?\d+(?:\.\d+)?)$/g, '$1px'); } }); /** * @overview *

This file defines a set of transition effects for hiding and showing overlay elements. * follow the pattern outlined below to implement your own custom transitions.

*/ Ojay.Overlay.Transitions .add('none', { hide: function(overlay, chain) { overlay.getContainer().hide(); chain.fire(); return overlay; }, show: function(overlay, chain) { overlay.getContainer() .setStyle({opacity: overlay.getOpacity()}) .setStyle(overlay.getSize(true)) .setStyle(overlay.getPosition(true)) .show(); chain.fire(); return overlay; } }) .add('fade', { hide: function(overlay, chain) { overlay.getContainer() .animate({opacity: {to: 0}}, Ojay.Overlay.TRANSITION_TIME) .hide() ._(chain.toFunction()); return chain; }, show: function(overlay, chain) { overlay.getContainer() .setStyle({opacity: 0}) .setStyle(overlay.getSize(true)) .setStyle(overlay.getPosition(true)) .show() .animate({opacity: {to: overlay.getOpacity()}}, Ojay.Overlay.TRANSITION_TIME) ._(chain.toFunction()); return chain; } }) .add('zoom', { hide: function(overlay, chain) { var region = overlay.getRegion().scale(0.5), center = region.getCenter(); overlay.getContainer() .animate({ opacity: {to: 0}, left: {to: region.left}, width: {to: region.getWidth()}, top: {to: region.top}, height: {to: region.getHeight()} }, Ojay.Overlay.TRANSITION_TIME, {easing: Ojay.Overlay.EASING}) .hide() ._(chain.toFunction()); return chain; }, show: function(overlay, chain) { var position = overlay.getPosition(), size = overlay.getSize(); overlay.getContainer() .setStyle({ opacity: 0, left: (position.left + size.width/4) + 'px', top: (position.top + size.height/4) + 'px', width: (size.width / 2) + 'px', height: (size.height / 2) + 'px' }) .show() .animate({ opacity: {to: overlay.getOpacity()}, left: {to: position.left}, width: {to: size.width}, top: {to: position.top}, height: {to: size.height} }, Ojay.Overlay.TRANSITION_TIME, {easing: Ojay.Overlay.EASING}) ._(chain.toFunction()); return chain; } }); /** *

The ContentOverlay class extends Overlay and provides the most generally * useful form of overlay. Much of its API it inherits from Overlay, but it provides a * few methods for dealing with changing the HTML content of an overlay. The markup generated by * the constructor is slightly different, as it contains an extra element for holding the content:

* *
     <div class="overlay-container">
 *         <div class="overlay-content">
 *             <!-- Content goes here -- >
 *         </div>
 *     </div>
* * @constructor * @class ContentOverlay */ Ojay.ContentOverlay = new JS.Class('Ojay.ContentOverlay', Ojay.Overlay, /** @scope Ojay.ContentOverlay.prototype */{ extend: /** @scope Ojay.ContentOverlay */{ CONTENT_CLASS: 'overlay-content' }, /** *

Initializes the overlay. Options are the same as for Overlay with one * addition: content specifies the initial HTML content of the overlay.

* @params {Object} options */ initialize: function(options) { this.callSuper(); this.setContent(this._options.content); }, /** *

Returns a DomCollection wrapping the HTML elements for the overlay.

* @returns {DomCollection} */ getHTML: function() { var self = this, elements = self._elements; if (elements._content) return elements._container; var container = this.callSuper().node, builder = new Ojay.HtmlBuilder(container); elements._content = Ojay( builder.div({className: self.klass.CONTENT_CLASS}) ); return elements._container; }, /** *

Sets the content of the overlay. May be a string or an HTMLElement.

* @param {String|HTMLElement} content * @returns {Overlay} */ setContent: function(content) { if (this.inState('CLOSED')) return this; this._elements._content.setContent(content || ''); return this; }, /** *

Returns a reference to the content-holding element of the overlay, wrapped in * a DomCollection. * @returns {DomCollection} */ getContentElement: function() { return this._elements._content; }, /** *

Inserts new content into the overlay, using the same syntax as for * DomCollection#insert().

* @param {String|HTMLElement} content * @param {String} position * @returns {Overlay} */ insert: function(content, position) { if (this.inState('CLOSED')) return this; this._elements._content.insert(content, position); return this; }, states: /** @scope Ojay.ContentOverlay.prototype */{ /** *

An overlay is in the INVISIBLE state when it is present in the document * but is not visible.

*/ INVISIBLE: /** @scope Ojay.ContentOverlay.prototype */{ /** *

Sets the size of the overlay to just contain its content.

* @returns {ContentOverlay} */ fitToContent: whileHidden('fitToContent') }, /** *

An overlay is in the VISIBLE state when it is present in the document * and visible.

*/ VISIBLE: /** @scope Ojay.ContentOverlay.prototype */{ /** *

Sets the size of the overlay to just contain its content.

* @param {Object} options * @returns {ContentOverlay} */ fitToContent: function(options) { var options = options || {}, animate = !!options.animate, balance = !!options.balance, innerRegion = this._elements._content.getRegion(), outerRegion = this.getRegion(); if (balance) innerRegion.centerOn(outerRegion); if (animate) return this.resize(innerRegion, options); this.setSize(innerRegion.getWidth(), innerRegion.getHeight()); this.setPosition(innerRegion.left, innerRegion.top); return this; } } } }); /** *

Tooltip is a subclass of ContentOverlay that provides overlays that * automatically follow the mouse pointer when visible. This class is very small and most * of its API comes from ContentOverlay and Overlay before it.

* @constructor * @class Tooltip */ Ojay.Tooltip = new JS.Class('Ojay.Tooltip', Ojay.ContentOverlay, /** @scope Ojay.Tooltip.prototype */{ /** *

Initializes the tooltip. The constructor differs from that of its parent classes * in that you must pass in the text for the tooltip as the first argument, followed * by the options hash.

* @param {String} text * @param {Object} options */ initialize: function(text, options) { this.callSuper(options); this._elements._container.addClass('tooltip'); this.setContent(text); this.klass._instances.push(this); }, extend: /** @scope Ojay.Tooltip */{ /** *

Updates the position of all tooltips.

* @param {Document} doc * @param {Event} evnt */ update: function(doc, evnt) { var xy = YAHOO.util.Event.getXY(evnt); this._instances.forEach(function(tooltip) { var region = tooltip.getRegion(); width = region ? region.getWidth() : this.DEFAULT_WIDTH; tooltip.setPosition(xy[0] + this.MOUSE_OFFSET - width / 2, xy[1] + this.MOUSE_OFFSET); }, this); }, /** *

Tooltip maintains a list of all its instances in order to update * their positions.

*/ _instances: [], DEFAULT_WIDTH: 100, MOUSE_OFFSET: 20 } }); Ojay(document).on('mousemove', Ojay.Tooltip.method('update')); /** *

The PageMask class is a subtype of Overlay that represents elements used * to obscure the rest of the document while an overlay is visible. This allows easy creation of * 'modal' windows and lightbox-style interfaces. The HTML generated is the same as for Overlay. * The main features added by PageMask are automatic sizing to fill the viewport, and * color control.

* @constructor * @class PageMask */ Ojay.PageMask = new JS.Class('Ojay.PageMask', Ojay.Overlay, /** @scope Ojay.PageMask.prototype */{ extend: /** @scope Ojay.PageMask */{ DEFAULT_COLOR: '000000', DEFAULT_OPACITY: 0.5, _instances: [], /** * */ resizeAll: function() { this._instances.forEach('setSize'); } }, /** *

Initializes the mask. Options are the same as for Overlay, with a single * addition: color sets the background color of the mask.

* @param {Object} options */ initialize: function(options) { this.klass._instances.push(this); this.callSuper(); this.setColor(this._options.color); if (!YAHOO.env.ua.ie) this._elements._container.setStyle({position: 'fixed'}); }, /** *

PageMask overrides setPosition() so that the mask is always positioned * at the top-left corner of the screen. The overlay is position 'fixed' in supporting * user agents.

* @returns {PageMask} */ setPosition: function() { return this.callSuper(0, 0); }, /** *

PageMask overrides setSize() so that the mask always completely covers * the visible area of the document.

* @returns {PageMask} */ setSize: function() { if (!YAHOO.env.ua.ie) return this.callSuper('100%', '100%'); var doc = Ojay(document.body).getRegion(), win = Ojay.getViewportSize(); return this.callSuper(Math.max(doc.getWidth(), win.width), Math.max(doc.getHeight(), win.height)); }, /** *

Sets the background color of the mask. Can be three separate numbers from 0 to 255 * (representing red, green and blue) or a single string representing all three as a hex * value.

* @param {String} color * @returns {PageMask} */ setColor: function(color) { this._color = (arguments.length == 3) ? Array.from(arguments).map(function(x) { var part = Math.round(x % 256).toString(16); return (part.length == 1 ? '0' : '') + part; }).join('') : (color ? String(color).replace(/[^0-9a-f]/ig, '') : this.klass.DEFAULT_COLOR); this._elements._container.setStyle({backgroundColor: '#' + this._color}); return this; }, states: /** @scope Ojay.PageMask.prototype */{ /** *

An overlay is in the INVISIBLE state when it is present in the document * but is not visible.

*/ INVISIBLE: /** @scope Ojay.PageMask.prototype */{ /** *

PageMask overrides INVISIBLE#show() to make sure the mask * is sized correctly before being made visible.

* @returns {MethodChain} */ show: function() { this.setSize(); return this.callSuper(); } } } }); if (YAHOO.env.ua.ie) Ojay(window).on('resize', Ojay.PageMask.method('resizeAll')); })(Ojay);_application/x-javascriptO.bplist00z{X$versionX$objectsY$archiverT$top("()0!12TUVWXYZ[\]^_`abcdefghijklmnoptuU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1&'#$%&[NS.relativeWNS.base_4https://cdn.othermedia.com/ojay/0.4.1/pkg/overlay.js*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#AD3456EWNS.keysZNS.objects%789:;<=>?@ABCD FGHIJKLMNOPQRS !"#$VServerZConnectionZKeep-Alive_Content-EncodingTVary\Content-TypeWExpires]Cache-Control]Accept-Ranges_X-Ua-Compatible]Last-ModifiedWX-CacheTDate^Content-LengthVApacheZKeep-Alive_timeout=2, max=100Tgzip_Accept-Encoding,U_application/x-javascript_Fri, 08 Oct 2021 17:18:04 GMT_max-age=315360000Ubytes]IE=EmulateIE7_Thu, 25 Jun 2009 14:45:22 GMT_MISS from cdn.othermedia.com_Tue, 11 Oct 2011 17:18:04 GMTT7885*+qr_NSMutableDictionaryqs/\NSDictionary*+vw_NSHTTPURLResponsexy/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiver|}_WebResourceResponse#-27bh %09?BHQZ\ckvx&4FT\apw3Rrw|~_4https://cdn.othermedia.com/ojay/0.4.1/pkg/overlay.js|}~O/* Copyright (c) 2007-2008 the OTHER media Limited Licensed under the BSD license, http://ojay.othermedia.org/license.html Version: 0.4.1 Build: source */ /** *

The Paginator class is used to replace large blocks of content with a smaller, * scrollable area with an API for controlling the area. The content will typically be made up * of series of items of the same size that can be grouped into pages. For example, an image * gallery could be set up as a series of floated divs or a list...

* * <div id="gallery"> * <div class="item"><img src="01.jpg" /></div> * <div class="item"><img src="02.jpg" /></div> * <div class="item"><img src="03.jpg" /></div> * <div class="item"><img src="04.jpg" /></div> * <div class="item"><img src="05.jpg" /></div> * <div class="item"><img src="06.jpg" /></div> * <div class="item"><img src="07.jpg" /></div> * <div class="item"><img src="08.jpg" /></div> * </div> * *

A Paginator, when applied to #gallery, will wrap its child elements in * a scrollable element that can be controlled using the Paginator API. So, your markup * will now look like:

* * <div class="paginator"> * <div id="gallery"> * <div class="page"> * <div class="item"><img src="01.jpg" /></div> * <div class="item"><img src="02.jpg" /></div> * <div class="item"><img src="03.jpg" /></div> * </div> * <div class="page"> * <div class="item"><img src="04.jpg" /></div> * <div class="item"><img src="05.jpg" /></div> * <div class="item"><img src="06.jpg" /></div> * </div> * <div class="page"> * <div class="item"><img src="07.jpg" /></div> * <div class="item"><img src="08.jpg" /></div> * </div> * </div> * </div> * *

The outer element is referred to as the 'container', and the inner element the 'subject'. * Paginator objects publish a number of events -- they are as follows:

* *
    *
  • pagechange - when the current page number changes
  • *
  • scroll when any scrolling takes place
  • *
  • firstpage - when the paginator reaches the first page
  • *
  • lastpage - when the paginator reaches the last page
  • *
  • focusitem - when focusItem() is called
  • *
* *

See the website for further documentation and graphical examples.

* * @constructor * @class Paginator */ Ojay.Paginator = new JS.Class('Ojay.Paginator', /** @scope Ojay.Paginator.prototype */{ include: [Ojay.Observable, JS.State], extend: /** @scope Ojay.Paginator */{ CONTAINER_CLASS: 'paginator', PAGE_CLASS: 'page', ITEM_CLASS: 'item', SCROLL_TIME: 0.5, PUSH_FADE_TIME: 0.7, PUSH_SLIDE_TIME: 0.3, DIRECTION: 'horizontal', EASING: 'easeBoth', /** * @param {Number} width * @param {Number} height * @returns {DomCollection} */ makePageElement: function(width, height) { var div = Ojay( Ojay.HTML.div({className: this.PAGE_CLASS}) ); div.setStyle({ 'float': 'left', width: width + 'px', height: height + 'px', margin: '0 0 0 0', padding: '0 0 0 0', border: 'none' }); return div; } }, /** *

To initialize, the Paginator instance needs a CSS selector and some configuration * options. Available options are:

* *
    *
  • width - the width as a string, in any units, e.g. '512px'. Required.
  • *
  • height - the height as a string, in any units, e.g. '512px'. Required.
  • *
  • scrollTime - the duration of the scoll effect in seconds. Optional.
  • *
  • easing - sets the name of the easing effect to use. Optional.
  • *
  • direction - 'horizontal' or 'vertical', sets scroll direction. Required.
  • *
* * @param {String|HTMLElement|DomCollection} subject * @param {Object} options */ initialize: function(subject, options) { this._selector = subject; this._elements = {}; options = this._options = options || {}; options.scrollTime = options.scrollTime || this.klass.SCROLL_TIME; options.pushFade = options.pushFade || this.klass.PUSH_FADE_TIME; options.pushSlide = options.pushSlide || this.klass.PUSH_SLIDE_TIME; options.direction = options.direction || this.klass.DIRECTION; options.easing = options.easing || this.klass.EASING; options.looped = !!options.looped; options.infinite = !!options.infinite; this.setState('CREATED'); }, /** * @returns {Object} */ getInitialState: function() { return {page: 1}; }, /** * @param {Object} state * @param {Function} callback * @param {Object} scope * @returns {Paginator} */ changeState: function(state, callback, scope) { if (state.page !== undefined) this._handleSetPage(state.page, callback, scope); return this; }, /** *

Returns an Ojay collection wrapping all the HTML used by the paginator.

* @returns {DomCollection} */ getHTML: function() { var elements = this._elements, options = this._options; if (elements._container) return elements._container; var container = Ojay( Ojay.HTML.div({className: this.klass.CONTAINER_CLASS}) ); container.addClass(this._options.direction); var width = options.width, height = options.height, items; if (options.rows || options.columns) { items = this.getItems(); if (options.rows) height = (options.rows * items.getHeight()) + 'px'; if (options.columns) width = (options.columns * items.getWidth()) + 'px'; } container.setStyle({ width: width, height: height, overflow: 'hidden', padding: '0 0 0 0', border: 'none', position: 'relative' }); return elements._container = container; }, /** *

Returns the direction of the paginator.

* @returns {String} */ getDirection: function() { return this._options.direction; }, /** *

Returns a boolean to indicate whether the paginator loops.

* @returns {Boolean} */ isLooped: function() { return !!this._options.looped || !!this._options.infinite; }, /** *

Returns an Ojay collection wrapping the wrapper element added to your document to * contain the original content element and let it slide.

* @returns {DomCollection} */ getContainer: function() { return this.getHTML(); }, /** *

Returns an Ojay collection wrapping the sliding element, i.e. the element you specify * when creating the Paginator instance.

* @returns {DomCollection} */ getSubject: function() { return this._elements._subject || undefined; }, /** *

Returns a Region object representing the area of the document occupied by * the Paginator's container element.

* @returns {Region} */ getRegion: function() { if (!this._elements._container) return undefined; return this._elements._container.getRegion(); }, /** * @returns {Number} */ getTotalOffset: function() { var method = (this._options.direction == 'vertical') ? 'getHeight' : 'getWidth'; return this.getRegion()[method]() * (this._numPages - 1); }, /** * @returns {Number} */ getCurrentOffset: function() { return this._reportedOffset; }, /** *

Returns an Ojay collection wrapping the child elements of the subject.

* @returns {DomCollection} */ getItems: function() { var elements = this._elements; if (!elements._subject) return undefined; if (elements._items) return elements._items; elements._items = elements._subject.children(this._options.selector); elements._items.setStyle({margin: '0 0 0 0'}); return elements._items; }, /** *

Returns the number of pages of content the Paginator has.

* @returns {Number} */ getPages: function() { if (this._numPages) return this._numPages; var items = this.getItems(); if (!items) return undefined; if (items.length === 0) return 0; var containerRegion = this.getRegion(), itemRegion = items.at(0).getRegion(); this._itemWidth = itemRegion.getWidth(); this._itemHeight = itemRegion.getHeight(); this._itemsPerCol = (containerRegion.getHeight() / this._itemHeight).floor() || 1; this._itemsPerRow = (containerRegion.getWidth() / this._itemWidth).floor() || 1; this._itemsPerPage = this._itemsPerRow * this._itemsPerCol; this._numPages = (items.length / this._itemsPerPage).ceil(); if (this._options.grouping !== false) this._groupItemsByPage(); return this._numPages; }, /** *

Splits the list of item elements into groups by page, and wraps each group of items * in a div that represents the page. This allows horizontal galleries to avoid * stringing all the items onto one row.

*/ _groupItemsByPage: function() { var containerRegion = this.getRegion(), width = containerRegion.getWidth(), height = containerRegion.getHeight(), n = this._itemsPerPage, allItems = this._elements._items.toArray(); this._elements._pages = []; this._numPages.times(function(i) { var items = allItems.slice(i * n, (i+1) * n); var div = this.klass.makePageElement(width, height); items.forEach(div.method('insert')); this._elements._pages.push(div); this._elements._subject.insert(div.node); }, this); this._dummyPage = this.klass.makePageElement(width, height); }, /** *

Returns the number of the current page, numbered from 1.

* @returns {Number} */ getCurrentPage: function() { return this._currentPage || undefined; }, /** *

Returns the page number containing the nth child element. Pages and items are * both numbered from 1 upwards.

* @param {Number} id * @returns {Number} */ pageForItem: function(id) { if (!this._numPages) return undefined; var n = this._elements._items.length; if (id < 1 || id > n) return undefined; return ((id - 1) / this._itemsPerPage).floor() + 1; }, /** *

Places a default set of UI controls before or after the Paginator in the * document and returns a Paginator.Controls instance representing this UI.

* @returns {Paginator.Controls} */ addControls: function(position) { if (this.inState('CREATED') || !/^(?:before|after)$/.test(position)) return undefined; var controls = new this.klass.Controls(this); this.getContainer().insert(controls.getHTML().node, position); return controls; }, states: { /** *

The Paginator is in the CREATED state when it has been instantiated but * none of its DOM interactions have taken place. This attachment is deferred to the * setup() call so that object can be history-managed before its UI is set up.

*/ CREATED: /** @scope Ojay.Paginator.prototype */{ /** *

Sets up all the DOM changes the Paginator needs. If you want to history * manage the object, make sure you set up history management before calling this method. * Moves the object to the READY state if successful.

* @returns {Paginator} */ setup: function() { var subject = this._elements._subject = Ojay(this._selector).at(0); if (!subject.node) return this; var container = this.getHTML(); subject.insert(container.node, 'after'); container.insert(subject.node); subject.setStyle({padding: '0 0 0 0', border: 'none', position: 'absolute', left: 0, right: 0}); var pages = this._numPages = this.getPages(), region = this.getRegion(); var style = (this._options.direction == 'vertical') ? { width: region.getWidth() + 'px', height: (pages * region.getHeight() + 1000) + 'px' } : { width: (pages * region.getWidth() + 1000) + 'px', height: region.getHeight() + 'px' }; subject.setStyle(style); var state = this.getInitialState(); this.setState('READY'); if (this._currentPage === undefined) this._currentPage = state.page; this._handleSetPage(this._currentPage); return this; }, /** *

Sets the initial page for the paginator to start at when in the CREATED * state. No scrolling takes place, and the number set will override the initial * page setting and any setting pulled in by the history manager.

* @param {Number} page * @returns {Paginator} */ setPage: function(page) { this._currentPage = Number(page); return this; } }, /** *

The Paginator is in the READY state when all its DOM behaviour has been * set up and it is not in the process of scrolling.

*/ READY: /** @scope Ojay.Paginator.prototype */{ /** *

Sets the current page of the Paginator by scrolling the subject * element. Will fire a pagechange event if the page specified is not * equal to the current page.

* @param {Number} page * @param {Function} callback * @param {Object} scope * @returns {Paginator} */ setPage: function(page, callback, scope) { page = Number(page); if (this._options.looped && page < 1) page += this._numPages; if (this._options.looped && page > this._numPages) page -= this._numPages; if (!this.isLooped() && (page == this._currentPage || page < 1 || page > this._numPages)) return this; this.changeState({page: page}, callback, scope); return this; }, /** *

Handles request to changeState().

* @param {Number} page * @param {Function} callback * @param {Object} scope */ _handleSetPage: function(page, callback, scope) { this.setScroll(this.getTotalOffset() * (page - 1) / (this._numPages - 1), {animate: true}, callback, scope); }, /** *

Increments the current page by one, firing a pagechange event.

* @returns {Paginator} */ incrementPage: function() { var wrapping = this._options.infinite && (this._currentPage == this._numPages), firstPage = this._elements._pages[0]; if (wrapping) this._elements._subject .insert(firstPage, 'bottom') .insert(this._dummyPage, 'top'); return this.setPage(this._currentPage + 1, function() { if (!wrapping) return; this._dummyPage.remove(); this._elements._subject.insert(firstPage, 'top'); this.setScroll(0, {animate: false, silent: true}); }, this); }, /** *

Decrements the current page by one, firing a pagechange event.

* @returns {Paginator} */ decrementPage: function() { var wrapping = this._options.infinite && (this._currentPage == 1), property = (this._options.direction == 'vertical') ? 'marginTop' : 'marginLeft', lastPage = this._elements._pages[this._numPages - 1], settings = {}; if (wrapping) { this._elements._subject.insert(lastPage, 'top'); settings[property] = (-this.getTotalOffset() / (this._numPages - 1)) + 'px'; this._elements._subject.setStyle(settings); } return this.setPage(this._currentPage - 1, function() { if (!wrapping) return; this._elements._subject.insert(lastPage, 'bottom'); settings[property] = 0; this._elements._subject.setStyle(settings); this.setScroll(1, {animate: false, silent: true}); }, this); }, /** *

Snaps the scroll offset of the Paginator to that of the current * page. The optional animate parameter, if set to false, will * prevent animation.

* @param {Boolean} animate * @returns {Paginator} */ snapToPage: function(animate) { this.setScroll((this._currentPage - 1) / (this._numPages - 1), {animate: animate !== false, silent: true}); return this; }, /** *

Scrolls to the page for the given item (numbered from 1) and adds a class * off focused to that item's element.

* @param {Number} id * @returns {Paginator} */ focusItem: function(id) { var page = this.pageForItem(id); if (!page) return this; var element = this._elements._items.at(id - 1); this.notifyObservers('focusitem', id, element); this.setPage(page); this._elements._items.removeClass('focused'); element.addClass('focused'); return this; }, /** *

Sets the scroll offset of the subject element. If amount is between * 0 and 1, it is taken as a fraction of the total offset. If it is greater than 1, * it is taken as an absolute pixel value. The options hash may specify animate, * to say whether the scroll move should be animated, and silent, which if * set to true will prevent any scroll events from firing.

* @param {Number} amount * @param {Object} options * @param {Function} callback * @param {Object} scope * @returns {Paginator} */ setScroll: function(amount, options, callback, scope) { var options = options || {}, orientation = this._options.direction, scrollTime = options._scrollTime || this._options.scrollTime, pages = this._numPages, total = this.getTotalOffset(), chain = new JS.MethodChain(), settings; if (amount >= 0 && amount <= 1) amount = amount * total; this._elements._items.removeClass('focused'); options = options || {}; if (options.animate && YAHOO.util.Anim) { this.setState('SCROLLING'); settings = (orientation == 'vertical') ? { top: {to: -amount} } : { left: {to: -amount} }; this._elements._subject.animate(settings, scrollTime, {easing: this._options.easing})._(function(self) { self.setState('READY'); chain.fire(scope || self); if (callback) callback.call(scope || null); }, this); } else { settings = (orientation == 'vertical') ? { top: (-amount) + 'px' } : { left: (-amount) + 'px' }; this._elements._subject.setStyle(settings); } var reportedOffset = amount/total; if (reportedOffset < 0) reportedOffset = 1; if (reportedOffset > 1) reportedOffset = 0; this._reportedOffset = amount; if (!options.silent) this.notifyObservers('scroll', reportedOffset, total); var page = (pages * reportedOffset).ceil() || 1; if (page != this._currentPage) { this._currentPage = page; this.notifyObservers('pagechange', page); if (page == 1) this.notifyObservers('firstpage'); if (page == pages) this.notifyObservers('lastpage'); } return (options.animate && YAHOO.util.Anim) ? chain : this; }, /** *

Pushes a new element onto the end of the list of elements contained in the * Paginator, creating a new page and firing the pagecreate * event if necessary. The n parameter is for internal use only, for when * items need to be moved across page boundaries by shift/unshift * operations.

* @param {HTMLElement} element * @param {Number} n * @returns {Paginator} */ push: function(element, n) { n = (n === undefined) ? this._numPages - 1 : n; var last = (n === this._numPages - 1); if (last) this._checkPages(); element = Ojay(element).setStyle({margin: '0 0 0 0'}); var page = this._elements._pages[last ? this._numPages - 1 : n]; page.insert(element, 'bottom'); this.notifyObservers('itemadd'); var items = this._elements._items; if (last) [].push.call(items, element.node); return this; }, /** *

Removes the final item from the final page of the Paginator. If * the final page subsequently contains no items, it is removed and a * pagedestroy event is fired. The n parameter is for internal * use only, for when items need to be moved across page boundaries by * shift/unshift operations.

* @param {Number} n * @returns {DomCollection} */ pop: function(n) { n = (n === undefined) ? this._numPages - 1 : n; var last = (n === this._numPages - 1); var page = this._elements._pages[n], item = Ojay(page.children().toArray().pop()); this.notifyObservers('itemremove'); if (!last) return item.remove(); this._elements._items = this._elements._items.filter(function(member) { return member.node !== item.node; }); if (last) this._checkPages(); return item.remove(); }, /** *

Removes the first item from the first page of the Paginator. If * the final page subsequently contains no items, it is removed and a * pagedestroy event is fired. The n parameter is for internal * use only, for when items need to be moved across page boundaries by * shift/unshift operations.

* @param {Number} n * @returns {DomCollection} */ shift: function(n) { n = (n === undefined) ? 0 : n; var first = (n === 0); var page = this._elements._pages[n], item = page.children().at(0); this.notifyObservers('itemremove'); if (!first) return item.remove(); for (var i = 1; i < this._numPages; i++) this.push(this.shift(i), i-1); this._elements._items = this._elements._items.filter(function(member) { return member.node !== item.node; }); this._checkPages(); return item.remove(); }, /** *

Pushes a new element onto the start of the list of elements contained in the * Paginator, creating a new page and firing the pagecreate * event if necessary. The n parameter is for internal use only, for when * items need to be moved across page boundaries by shift/unshift * operations.

* @param {HTMLElement} element * @param {Number} n * @returns {Paginator} */ unshift: function(element, n) { if (typeof n == 'object' && n.animate) return this._animatedUnshift(element); n = (n === undefined) ? 0 : n; var first = (n === 0); if (first) this._checkPages(); element = Ojay(element).setStyle({margin: '0 0 0 0'}); var page = this._elements._pages[n]; page.insert(element, 'top'); this.notifyObservers('itemadd'); if (!first) return this; for (var i = 1; i < this._numPages; i++) this.unshift(this.pop(i-1), i); var items = this._elements._items; [].unshift.call(items, element.node); return this; }, /** * @returns {MethodChain} */ _animatedUnshift: function(element) { if ((this._options.direction == 'vertical' && this._itemsPerRow > 1) || (this._options.direction == 'horizontal' && this._itemsPerCol > 1)) throw new Error('Cannot perform animated push/unshift ' + 'onto a Paginator with more than one ' + 'column and row'); var item = Ojay(element).setStyle({opacity: 0}); var current = this.getCurrentOffset(), nItems = (this._options.direction == 'vertical') ? this._itemsPerCol : this._itemsPerRow, offset = current - this.getTotalOffset() / (nItems * (this.getPages() - 1)); return this.setScroll(offset, {animate: true, _scrollTime: this._options.pushSlide}) .unshift(item) .setScroll(current) ._(item).animate({opacity: {to: 1}}, this._options.pushFade) ._(this); }, /** *

Used by the push, pop, shift and unshift * operations to decide whether pages need to be created or destroyed.

*/ _checkPages: function() { var items = this._elements._items.length, pages = this._numPages, perPage = this._itemsPerPage, total = pages * perPage; if (items == total) this._createPage(); if (items == total - perPage) this._destroyPage(); }, /** *

Adds a new page at the end of the Paginator, firing the * pagecreate and scroll events.

*/ _createPage: function() { var region = this.getRegion(), page = this.klass.makePageElement(region.getWidth(), region.getHeight()); this._elements._subject.insert(page, 'bottom'); this._elements._pages.push(page); this._numPages += 1; var offset = (this._currentPage - 1) / (this._numPages - 1); this.notifyObservers('pagecreate'); this.notifyObservers('scroll', offset, this.getTotalOffset()); }, /** *

Removes the final page of the Paginator, firing the * pagedestroy, scroll and (if needed) the * pagechange events. */ _destroyPage: function() { this._elements._pages.pop().remove(); if (this._currentPage == this._numPages) { this._currentPage -= 1; this.notifyObservers('pagechange', this._currentPage); } this._numPages -= 1; var offset = (this._currentPage - 1) / (this._numPages - 1); if (offset == 1) this.setScroll(1, {animate: true, silent: true}); this.notifyObservers('pagedestroy'); this.notifyObservers('scroll', offset, this.getTotalOffset()); } }, SCROLLING: {} } }); /** *

The AjaxPaginator class extends the Paginator with functionality that * allows you to load content for the pages from the server using Ajax. Content is lazy-loaded, * which is to say that each page is not loaded until the user selects to view that page.

* @constructor * @class AjaxPaginator */ Ojay.AjaxPaginator = new JS.Class('Ojay.AjaxPaginator', Ojay.Paginator, /** @scope Ojay.AjaxPaginator.prototype */{ /** *

AjaxPaginator takes the same initialization data as Paginator, but * with one extra required option: urls. This should be an array of URLs that * the paginator will pull content from.

* @param {String|HTMLElement|DomCollection} subject * @param {Object} options */ initialize: function(subject, options) { this.callSuper(); this._options.urls = this._options.urls.map(function(url) { return {_url: url, _loaded: false}; }); }, /** *

Returns an Ojay collection wrapping the child elements of the subject.

* @returns {DomCollection} */ getItems: function() { var elements = this._elements; if (elements._items) return elements._items; if (!elements._subject) return undefined; var urls = this._options.urls; if (!urls.length) return undefined; urls.length.times(function(i) { var item = Ojay( Ojay.HTML.div({className: this.klass.ITEM_CLASS}) ); elements._subject.insert(item.node, 'bottom'); }, this); var items = this.callSuper(); items.fitToRegion(this.getRegion()); return items; }, /** *

Returns true iff the given page has its content loaded.

* @param {Number} page * @returns {Boolean} */ pageLoaded: function(page) { return !!(this._options.urls[page - 1]||{})._loaded; }, /** *

Tells the AjaxPaginator to load the content for the given page, if * the content is not already loaded. Fires pagerequest and * pageload events.

* @param {Number} page * @param {Function} callback * @param {Object} scope * @returns {AjaxPaginator} */ loadPage: function(page, callback, scope) { if (this.pageLoaded(page) || this.inState('CREATED')) return this; var url = this._options.urls[page - 1], self = this; this.notifyObservers('pagerequest', url._url); Ojay.HTTP.GET(url._url, {}, { onSuccess: function(response) { response.insertInto(self._elements._items.at(page - 1)); url._loaded = true; self.notifyObservers('pageload', url._url, response); if (typeof callback == 'function') callback.call(scope || null); } }); return this; }, states: { READY: { /** *

Handles request to changeState().

* @param {Number} page */ _handleSetPage: function(page) { var n = this._options.urls.length; if (page > n) page -= n; if (page < 1) page += n; if (this.pageLoaded(page)) return this.callSuper(); var _super = this.method('callSuper'); this.setState('REQUESTING'); this.loadPage(page, function() { this.setState('READY'); _super(); }, this); } }, REQUESTING: {} } }); /** *

The Paginator.Controls class implements a default UI for Paginator * instances, which includes previous/next links, individual page links, and event listeners * that add class names to the elements in the UI in response to state changes in the * observed paginator object.

* @constructor * @class Paginator.Controls */ Ojay.Paginator.extend(/** @scope Ojay.Paginator */{ Controls: new JS.Class('Ojay.Paginator.Controls', /** @scope Ojay.Paginator.Controls.prototype */{ extend: /** @scope Ojay.Paginator.Controls */{ CONTAINER_CLASS: 'paginator-controls', PREVIOUS_CLASS: 'previous', NEXT_CLASS: 'next', PAGE_LINKS_CLASS: 'pages' }, /** *

To initialize a Paginator.Controls instance, pass in the Paginator * to which you want the generated UI elements to apply.

* @param {Paginator} */ initialize: function(paginator) { this._paginator = paginator; this._elements = {}; this._paginator.on('pagecreate')._(this)._addPage(); this._paginator.on('pagedestroy')._(this)._removePage(); }, /** *

Returns the collection of HTML elements used to implement the UI. When the * elements are first generated, all required event handlers (both DOM and * Observable-based) are set up.

* @returns {DomCollection} */ getHTML: function() { if (this._paginator.inState('CREATED')) return null; var elements = this._elements, klass = this.klass, paginator = this._paginator; if (elements._container) return elements._container; var self = this; elements._container = Ojay( Ojay.HTML.div( {className: klass.CONTAINER_CLASS}, function(HTML) { // Previous button - decrements page elements._previous = Ojay( HTML.div( {className: klass.PREVIOUS_CLASS}, 'Previous') ); // Page buttons - skip to individual pages elements._pageLinks = Ojay( HTML.div( {className: klass.PAGE_LINKS_CLASS}, function(HTML) { elements._pages = []; paginator.getPages().times(function(page) { var span = elements._pages[page] = self._makeLink(page+1); HTML.concat(span.node); }); }) ); // Next button - increments page elements._next = Ojay( HTML.div( {className: klass.NEXT_CLASS}, 'Next') ); }) ); elements._previous.on('click')._(paginator).decrementPage(); elements._next.on('click')._(paginator).incrementPage(); // Delegate page click events to the container elements._pageLinks.on('click', Ojay.delegateEvent({ span: function(element, evnt) { paginator.setPage(element.node.innerHTML); } })); // Add hover states to previous and next buttons var buttons = [elements._previous, elements._next]; buttons.forEach(it().on('mouseover').addClass('hovered')); buttons.forEach(it().on('mouseout').removeClass('hovered')); // Monitor page changes to highlight page links paginator.on('pagechange', function(paginator, page) { this._highlightPage(page); buttons.forEach(it().removeClass('disabled')); }, this); var page = paginator.getCurrentPage(); this._highlightPage(page); // Disable previous and next buttons at the ends of the run if (!paginator.isLooped()) { paginator.on('firstpage')._(elements._previous).addClass('disabled'); paginator.on('lastpage')._(elements._next).addClass('disabled'); if (page == 1) elements._previous.addClass('disabled'); if (page == paginator.getPages()) elements._next.addClass('disabled'); } elements._container.addClass(paginator.getDirection()); return elements._container; }, /** *

Creates and returns an element to use as a numbered page link.

* @param {Number} page * @returns {DomCollection} */ _makeLink: function(page) { var link = Ojay( Ojay.HTML.span(String(page)) ); link.on('mouseover').addClass('hovered'); link.on('mouseout').removeClass('hovered'); return link; }, /** *

Responds to the pagecreate event on the associated Paginator * instance by adding a new page link to the list.

*/ _addPage: function() { var link = this._makeLink(this._paginator.getPages()); this._elements._pages.push(link); this._elements._pageLinks.insert(link, 'bottom'); this._elements._next.removeClass('disabled'); }, /** *

Responds to the pagedestroy event on the associated Paginator * instance removing the final page link from the list.

*/ _removePage: function() { this._elements._pages.pop().remove(); var pager = this._paginator; if (pager.isLooped()) return; if (pager.getCurrentPage() == pager.getPages()) this._elements._next.addClass('disabled'); }, /** *

Adds the class 'selected' to the current page number.

* @param {Number} */ _highlightPage: function(page) { this._elements._pages.forEach({removeClass: 'selected'}); this._elements._pages[page - 1].addClass('selected'); }, /** *

Returns a reference to the 'previous' button.

* @returns {DomCollection} */ getPreviousButton: function() { if (this._paginator.inState('CREATED')) return null; return this._elements._previous; }, /** *

Returns a reference to the 'next' button.

* @returns {DomCollection} */ getNextButton: function() { if (this._paginator.inState('CREATED')) return null; return this._elements._next; }, /** *

Returns a reference to the collection of page number links.

* @returns {DomCollection} */ getPageButtons: function() { if (this._paginator.inState('CREATED')) return null; return this._elements._pageLinks; } }) });_application/x-javascriptO0bplist00z{X$versionX$objectsY$archiverT$top("()0!12TUVWXYZ[\]^_`abcdefghijklmnoptuU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1&'#$%&[NS.relativeWNS.base_6https://cdn.othermedia.com/ojay/0.4.1/pkg/paginator.js*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#AD 3456EWNS.keysZNS.objects%789:;<=>?@ABCD FGHIJKLMNOPQRS !"#$VServerZConnectionZKeep-Alive_Content-EncodingTVary\Content-TypeWExpires]Cache-Control]Accept-Ranges_X-Ua-Compatible]Last-ModifiedWX-CacheTDate^Content-LengthVApacheZKeep-Alive_timeout=2, max=100Tgzip_Accept-Encoding,U_application/x-javascript_Fri, 08 Oct 2021 17:18:04 GMT_max-age=315360000Ubytes]IE=EmulateIE7_Thu, 25 Jun 2009 14:45:20 GMT_MISS from cdn.othermedia.com_Tue, 11 Oct 2011 17:18:04 GMTT8668*+qr_NSMutableDictionaryqs/\NSDictionary*+vw_NSHTTPURLResponsexy/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiver|}_WebResourceResponse#-27bh"'2;ADJS\^emxz(6HV^cry5Tty~~_6https://cdn.othermedia.com/ojay/0.4.1/pkg/paginator.jsO?B/* Copyright (c) 2007-2008 the OTHER media Limited Licensed under the BSD license, http://ojay.othermedia.org/license.html Version: 0.4.1 Build: source */ /** *

The Tabs class is used to convert a list of document sections into a tabbed * interface. Each section should contain a heading or similar common element whose content * will be used as the text label for each tab.

* *

For example, the following starting markup:

* *
    
*
*

J.G. Ballard

*

I believe in the power of the imagination to remake the * world, to release the truth within us, to hold back the night...

*
*
*

Andrei Tarkovsky

*

We do not move in one direction, rather do we wander back and * forth, turning now this way and now that. We go back on our own...

*
*
*

Philip K. Dick

*

I ask in my writing, What is real? Because unceasingly we * are bombarded with pseudo-realities manufactured...

*
*
* *

and the following script snippet:

* *
    var tabs = Ojay.Tabs('#tabGroup .tab');
 *     tabs.setup();
* *

the markup is transformed into:

* *
    
    *
  • J.G. Ballard
  • *
  • Andrei Tarkovsky
  • *
  • Philip K. Dick
  • *
*
*
*

I believe in the power of the imagination to remake the * world, to release the truth within us, to hold back the night...

*
*
*

We do not move in one direction, rather do we wander back and * forth, turning now this way and now that. We go back on our own...

*
*
*

I ask in my writing, What is real? Because unceasingly we * are bombarded with pseudo-realities manufactured...

*
*
* * @constructor * @class Tabs */ Ojay.Tabs = new JS.Class('Ojay.Tabs', /** @scope Ojay.Tabs.prototype */{ include: [Ojay.Observable, JS.State], /** *

To initialize, Tabs requires a CSS selector to get the list of page * sections to convert to tabs, and optionally an options object. Available options * are:

* *
    *
  • toggleSelector - CSS selector used to get toggle elements *
  • togglesClass - class name added to the generated list of toggles *
  • togglesPosition - 'before' or 'after', position to insert toggles list *
  • switchTime - duration of tab switch animation in seconds *
* * @param {String} tabs * @param {Object} options */ initialize: function(tabs, options) { this._tabGroup = tabs; options = options || {}; options.toggleSelector = options.toggleSelector || this.klass.TOGGLE_SELECTOR; options.togglesClass = options.togglesClass || this.klass.TOGGLES_CLASS; options.switchTime = options.switchTime || this.klass.SWITCH_TIME; options.togglesPosition = options.togglesPosition || this.klass.INSERT_POSITION; this._options = options; this.setState('CREATED'); }, /** * @returns {Object} */ getInitialState: function() { return {tab: 1}; }, /** * @param {Object} state * @param {Object} options * @returns {Tabs} */ changeState: function(state, options) { if (state.tab !== undefined) this._handleSetPage(state.tab, options); return this; }, states: { /** *

The Tabs instance is in the CREATED state until its setup() * method is called.

*/ CREATED: /** @scope Ojay.Tabs.prototype */{ /** *

Sets up all the DOM changes the Tabs object needs. If you want to history * manage the object, make sure you set up history management before calling this method. * Moves the object to the READY state if successful.

* @returns {Tabs} */ setup: function() { this._tabGroup = Ojay(this._tabGroup); this._container = this._tabGroup.parents().at(0); this._makeToggles(); this._makeViews(); this._restoreState(); return this; }, /** *

Insert the toggle control group before or after the tabs' containing * element.

*/ _makeToggles: function() { this._toggles = []; var self = this, options = self._options; var toggles = Ojay( Ojay.HTML.ul({className: options.togglesClass}, function (HTML) { self._tabGroup.children(options.toggleSelector).forEach(function(header, i) { var toggle = Ojay( HTML.li() ).addClass('toggle-' + (i+1)); toggle.setContent(header.node.innerHTML); if (i === 0) toggle.addClass('first'); if (i === self._tabGroup.length - 1) toggle.addClass('last'); self._toggles.push(toggle); header.remove(); toggle.on('click')._(self).setPage(i+1); }); }) ); if (typeof this._options.width != 'undefined') toggles.setStyle({width: this._options.width}); this._tabGroup.parents().at(0).insert(toggles, this._options.togglesPosition); }, _makeViews: function() { var self = this, options = self._options; this._tabs = this._tabGroup.map(function(container) { return new this.klass.Tab(this, container); }, this); if (options.width && options.height) this._container.setStyle({height: options.height}); }, _restoreState: function() { this.setState('READY'); var state = this.getInitialState(); this._handleSetPage(state.tab); this.on('pagechange', function(tabs, page) { tabs._highlightToggle(page - 1); }); } }, /** *

The Tabs object is in the READY state when all its DOM behaviour has been * set up and it is not in the process of switching tabs.

*/ READY: /** @scope Ojay.Tabs.prototype */{ /** *

Switches the set of tabs to the given page (indexed from 1), inserting * history entry. Passing in the silent option will stop the * pagechange event from being published.

* @param {Number} page * @param {Object} options * @returns {Tabs} */ setPage: function(page, options) { this.changeState({tab: page}, options); return this; }, /** *

Switch to the tab with the index provided as the first argument.

* @param {Number} index * @param {Object} options */ _handleSetPage: function(index, options) { index -= 1; if (index >= this._tabs.length) index = 0; if (this._currentTab == index) return; if ((options || {}).silent !== false) this.notifyObservers('pagechange', index+1); if (typeof this._currentTab == 'undefined') { this._currentTab = index; this._tabs[index].show(); this._highlightToggle(index); } else { this.setState('ANIMATING'); this._tabs[this._currentTab].hide()._(function(self) { self._currentTab = index; self._tabs[index].show() ._(self).setState('READY'); }, this); } }, /** *

Sets the 'selected' class on the appropriate toggle.

* @param {Number} index */ _highlightToggle: function(index) { this._toggles.forEach({removeClass: 'selected'}); this._toggles[index].addClass('selected'); } }, /** *

The Tabs instance is in the ANIMATING state during tab transitions.

*/ ANIMATING: /** @scope Ojay.Tabs.prototype */{} }, extend: /** @scope Ojay.Tabs */{ TOGGLE_SELECTOR: '.toggle', TOGGLES_CLASS: 'toggles', SWITCH_TIME: 0.2, INSERT_POSITION: 'before', /** * @constructor * @class Tab */ Tab: new JS.Class('Ojay.Tabs.Tab', /** @scope Ojay.Tabs.Tab.prototype */{ /** * @param {Ojay.Tab} group * @param {HTMLElement} container */ initialize: function(group, container) { this._container = container, this._group = group; this._container.hide().setStyle({opacity: 0}); if (this._group._options.height) this._container.setStyle({position: 'absolute', top: 0, left: 0}); }, /** * @returns {JS.MethodChain} */ hide: function() { return this._container.animate({opacity: {to: 0}}, this._group._options.switchTime) .hide() ._(this); }, /** * @returns {JS.MethodChain} */ show: function() { return this._container.show().animate({opacity: {to: 1}}, this._group._options.switchTime) ._(this); } }) } }); /** * @class AjaxTabs * @constructor */ Ojay.AjaxTabs = new JS.Class('Ojay.AjaxTabs', Ojay.Tabs, /** @scope Ojay.AjaxTabs.prototype */{ /** *

AjaxTabs takes slightly different initialization data to Tabs. * This class requires two compulsory arguments. The first is a list of link elements * (or a CSS selector for same); these links will become the toggles for the tab group. * The second is an element into which to insert the content retrieved by the Ajax * requests.

* @param {String|DomCollection} links * @param {String|DomCollection} container * @param {Object} options */ initialize: function(links, container, options) { this.callSuper(links, options); this._container = container; }, /** *

Returns true iff the given page is already loaded.

* @param {Number} index * @returns {Boolean} */ pageLoaded: function(index) { return !!this._loaded[index - 1]; }, /** *

Tells the AjaxTabs to load the content for the given page, if * the content is not already loaded. Fires pagerequest and * pageload events.

* @param {Number} page * @param {Function} callback * @param {Object} scope * @returns {AjaxTabs} */ loadPage: function(page, callback, scope) { if (this.pageLoaded(page) || this.inState('CREATED')) return this; var url = this._links[page - 1].href, self = this; this.notifyObservers('pagerequest', url); Ojay.HTTP.GET(url, {}, { onSuccess: function(response) { response.insertInto(self._tabGroup[page - 1]); self._loaded[page - 1] = true; self.notifyObservers('pageload', url, response); if (typeof callback == 'function') callback.call(scope || null); } }); return this; }, states: { CREATED: { /** *

Sets up all the DOM changes the Tabs object needs. If you want to history * manage the object, make sure you set up history management before calling this method. * Moves the object to the READY state if successful.

* @returns {Tabs} */ setup: function() { this._links = Ojay(this._tabGroup); this._loaded = this._links.map(function() { return false; }); this._container = Ojay(this._container); this._makeToggles(); this._makeViews(); this._restoreState(); return this; }, /** *

Sets up the links as toggles to control tab visibility.

*/ _makeToggles: function() { this._toggles = []; this._links.forEach(function(link, i) { link.addClass('toggle-' + (i+1)); if (i === 0) link.addClass('first'); if (i === this._links.length - 1) link.addClass('last'); this._toggles.push(link); link.on('click', Ojay.stopDefault)._(this).setPage(i+1); }, this); }, /** *

Generates a set of elements to hold the content retrieved over Ajax * when the links are clicked.

*/ _makeViews: function() { this._container.setContent(''); this._links.forEach(function(link, i) { var div = Ojay.HTML.div({className: this.klass.TAB_CLASS}); this._container.insert(div); }, this); this._tabGroup = this._container.children(); this.callSuper(); } }, READY: { /** *

Handles request to changeState().

* @param {Number} page */ _handleSetPage: function(index) { if (this.pageLoaded(index)) return this.callSuper(); var _super = this.method('callSuper'); this.setState('REQUESTING'); this.loadPage(index, function() { this.setState('READY'); _super(); }, this); } }, REQUESTING: {} }, extend: /** @scope Ojay.AjaxTabs */{ TAB_CLASS: 'tab', /** *

There's a pretty good chance of there being several good ways of instantiating * one of these, so for now let's encourage the default way to be used through a * factory method.

* @param {String|DomCollection} links * @param {String|DomCollection} container * @param {Object} options * @returns {AjaxTabs} */ fromLinks: function(links, container, options) { return new this(links, container, options); } } });_application/x-javascriptO*bplist00z{X$versionX$objectsY$archiverT$top("()0!12TUVWXYZ[\]^_`abcdefghijklmnoptuU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1&'#$%&[NS.relativeWNS.base_1https://cdn.othermedia.com/ojay/0.4.1/pkg/tabs.js*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#AD٣3456EWNS.keysZNS.objects%789:;<=>?@ABCD FGHIJKLMNOPQRS !"#$VServerZConnectionZKeep-Alive_Content-EncodingTVary\Content-TypeWExpires]Cache-Control]Accept-Ranges_X-Ua-Compatible]Last-ModifiedWX-CacheTDate^Content-LengthVApacheZKeep-Alive_timeout=2, max=99Tgzip_Accept-Encoding,U_application/x-javascript_Fri, 08 Oct 2021 17:18:04 GMT_max-age=315360000Ubytes]IE=EmulateIE7_Thu, 25 Jun 2009 14:45:22 GMT_MISS from cdn.othermedia.com_Tue, 11 Oct 2011 17:18:04 GMTT4039*+qr_NSMutableDictionaryqs/\NSDictionary?B*+vw_NSHTTPURLResponsexy/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiver|}_WebResourceResponse#-27bh"-6<?ENWY`hsu #1CQY^mt/Nnsx ~_1https://cdn.othermedia.com/ojay/0.4.1/pkg/tabs.jsO]/* Copyright (c) 2007-2008 the OTHER media Limited Licensed under the BSD license, http://ojay.othermedia.org/license.html Version: 0.4.1 Build: source */ /** * @overview *

Ojay.HTTP wraps the YAHOO.util.Connect module to provide a more succinct * API for making Ajax requests. It's called HTTP to emphasise what's actually going on * in an Ajax call: we're just making an HTTP request. Ojay.HTTP makes you use HTTP verbs * as methods, to make it clear what's going on to anyone reading the code. A quick example:

* *
    Ojay.HTTP.GET('/index.html', {ajaxLayout: true}, {
 *         onSuccess: function(response) {
 *             alert(response.responseText);
 *         }
 *     });
* *

This illustrates the basic pattern of making an HTTP request. Start with the verb (GET, * POST, PUT, DELETE or HEAD), then pass in the URL and the * parameters you want to send to the server. These parameters will be turned into a query string * or a POST message, depending on the verb used. The URL may contain a query string, but its * parameters will be overridden by the parameters object:

* *
    // Request is: GET /index.html?id=900&ajaxLayout=true
 *     Ojay.HTTP.GET('/index.html?id=45&ajaxLayout=true', {id: 900})
* *

You can define callbacks called onSuccess (fired on any reponse with a 2xx status * code), onFailure (fired on any 3xx, 4xx or 5xx response) or status-code-specific * callbacks, like on404:

* *
    Ojay.HTTP.POST('/posts/create', {title: '...'}, {
 *         onSuccess: function(response) {
 *             alert('Post created!');
 *         },
 *         on403: function(response) {
 *             alert('Permission denied!);
 *         }
 *     });
* *

The response object passed to your callbacks will be an instance of HTTP.Response, * which wraps the response object returned by YUI. It has convenience methods for manipulating * the response and inserting it into the document. Its methods are listed below. You can use the * response methods to chain after HTTP calls for more sentence-like code:

* *
    Ojay.HTTP.GET('/index.html').insertInto('#container').evalScripts();
* *

It's best to use this chaining for really simple stuff -- just remember the chain is called * asynchronously after the HTTP request completes, so any code following a chain like this should * not assume that the content has been inserted into the document or that the scripts have been * run.

* *
    Ojay.HTTP.GET('/index.html').insertInto('#container');  // asynchronous insertion
 *     var text = Ojay('#container').node.innerHTML;
 *             // text does NOT contain the HTTP response yet!
* *

For anything beyond really simple stuff, it's best to use explicit callback functions.

* *

HTTP.Response methods are available in chains following calls to on(), * animate() and wait() on DomCollection objects. e.g.:

* *
    Ojay('input[type=submit]').on('click')
 *             ._(Ojay.HTTP.POST, '/posts/update/34', ...)
 *             .insertInto('#message');
* *

You can even pass functions into the parameters object, and HTTP will execute them * at the time the request is made:

* *
    Ojay('#link').on('click')
 *             ._(Ojay.HTTP.POST, '/images/save_width', {width: Ojay('#foo').method('getWidth')});
* *

Ojay('#foo').method('getWidth') is a function bound to Ojay('#foo'); when * the POST request is made, it will be executed and the return value will be sent to the server * in the width parameter.

*/ Ojay.HTTP = new JS.Singleton('Ojay.HTTP', /** @scope Ojay.HTTP */{ include: Ojay.Observable, /** *

Object containing named references to XmlHttpRequest ready states.

*/ READY_STATE: { UNINITIALIZED: 0, LOADING: 1, LOADED: 2, INTERACTIVE: 3, COMPLETE: 4 }, /** *

List of verbs supported by Ojay.HTTP.

*/ VERBS: 'GET POST PUT DELETE HEAD'.split(/\s+/) }); Ojay.HTTP.VERBS.forEach(function(verb) { Ojay.HTTP[verb] = function(url, parameters, callbacks) { var request = new Ojay.HTTP.Request(verb, url, parameters, callbacks); request._begin(); return request.chain; }; }); /** *

The HTTP.Request class is used to instantiate Ajax calls to the server. This * is for internal consumption -- use HTTP.GET et al to make requests.

* @constructor * @class HTTP.Request */ Ojay.HTTP.Request = new JS.Class('Ojay.HTTP.Request', /** @scope Ojay.HTTP.Request.prototype */{ /** * @param {String} verb One of 'GET', 'POST', 'PUT', 'DELETE', or 'HEAD' * @param {String} url The URL to request * @param {Object} parameters Key-value pairs to be used as a query string or POST message; * alternatively, a string to be used as a POST request body. * @param {Object} callbacks Object containing callback functions */ initialize: function(verb, url, parameters, callbacks) { this.verb = verb.toUpperCase(); if (Ojay.HTTP.VERBS.indexOf(this.verb) == -1) return; this._url = url; this._parameters = parameters || {}; if (typeof callbacks != 'object') callbacks = {onSuccess: callbacks}; this._callbacks = callbacks || {}; this.chain = new JS.MethodChain(); }, /** *

Returns the URI of the request. */ getURI: function() { if (this.uri) return this.uri; var params = (typeof this._parameters == 'string') ? {} : this._parameters; return this.uri = Ojay.URI.build(this._url, params); }, /** *

Makes the HTTP request and sets up all the callbacks.

*/ _begin: function() { var post = (this.verb == 'POST'), uri = this.getURI(), url = post ? uri._getPathWithHost() : uri.toString(), postData = post ? this._getPostData(uri) : undefined; Ojay.HTTP.notifyObservers('request', {receiver: this}); YAHOO.util.Connect.asyncRequest(this.verb, url, { scope: this, // Will fire onSuccess, on2xx, and the chain success: function(transport) { var response = new Ojay.HTTP.Response(this, transport); var success = this._callbacks.onSuccess; var onStatus = this._callbacks['on' + response.status]; var complete = this._callbacks.onComplete; success && Function.from(success)(response); onStatus && Function.from(onStatus)(response); complete && Function.from(complete)(response); this.chain.fire(response); Ojay.HTTP.notifyObservers('success', {receiver: response}); Ojay.HTTP.notifyObservers(response.status, {receiver: response}); Ojay.HTTP.notifyObservers('complete', {receiver: response}); }, // Will fire onFailure, on3xx, on4xx, on5xx failure: function(transport) { var response = new Ojay.HTTP.Response(this, transport); var failure = this._callbacks.onFailure; var onStatus = this._callbacks['on' + response.status]; var complete = this._callbacks.onComplete; failure && Function.from(failure)(response); onStatus && Function.from(onStatus)(response); complete && Function.from(complete)(response); Ojay.HTTP.notifyObservers('failure', {receiver: response}); Ojay.HTTP.notifyObservers(response.status, {receiver: response}); Ojay.HTTP.notifyObservers('complete', {receiver: response}); } }, postData); }, /** * @param {URI} uri * @returns {String} */ _getPostData: function(uri) { return (typeof this._parameters == 'string') ? this._parameters : uri.getQueryString(); } }); /** *

The HTTP.Response class is used to wrap XmlHttpRequest transport objects in Ajax * callback functions. The argument passed into your Ajax callbacks, and used as the base of chains * after GET/POST/etc calls, will be an object of this class. It contains fields * copied straight from the transport object, including status, statusText, * responseText, and responseXML.

* class. * @constructor * @class HTTP.Response */ Ojay.HTTP.Response = new JS.Class('Ojay.HTTP.Response', /** @scope Ojay.HTTP.Response.prototype */{ /** * @param {HTTP.Request} request an HTTP.Request object * @param {Object} transport An XmlHttpRequest transport object */ initialize: function(request, transport) { 'status statusText responseText responseXML readyState'.split(/\s+/).forEach(function(key) { this[key] = transport[key]; }, this); this.request = request; this.transport = transport; }, /** *

Inserts the response's body text into the given elements at the given * position (default is 'replace'). See DomCollection#insert.. * If no position is specified, will accept any object with a setContent() method.

* @param {String|HTMLElement|DomCollection} elements * @param {String} position * @returns {HTTP.Response} */ insertInto: function(elements, position) { elements = elements.setContent ? elements : Ojay(elements); var content = (this.responseText || '').stripScripts(); if (!position) elements.setContent(content); else elements.insert(content, position); return this; }, /** * @returns {HTTP.Response} */ evalScripts: function() { if (this.responseText) this.responseText.evalScripts(); return this; }, /** *

Returns the result of parsing the response body as JSON.

* @returns {Object|Array} */ parseJSON: function() { return (this.responseText || '').parseJSON(); } }); (function() { var HTTP = Ojay.HTTP; // Precompiled regexps var PATTERNS = { JS: /\.js$/i, CSS: /\.css$/i }; var IFRAME_NAME = '__ojay_cross_domain__', JSONP_HANDLER_NAME = '__ojay_jsonp_handler__', HANDLER_COUNT = 0; var createIframe = function() { Ojay(document.body).insert('', 'top'); }.runs(1); var getHandlerId = function() { return JSONP_HANDLER_NAME + (HANDLER_COUNT++); }; var handleJsonP = function(callback, data) { var args = Array.from(arguments), callback = args.shift(); callback.apply(null, args); }; var removeHandler = function(id) { window[id] = null; try { delete window[id] } catch (e) {} }.curry(); var determineAssetType = function(url) { switch (true) { case PATTERNS.JS.test(url) : return 'script'; break; case PATTERNS.CSS.test(url) : return 'css'; break; default : return 'script'; break; } }; JS.extend(HTTP, /** @scope Ojay.HTTP */{ /** *

Ojay.HTTP.GET is overloaded to provide support for YAHOO.util.Get, * which allows loading of new script/css assets into the document, even from other domains. * If you try to GET a URL from another domain, Ojay automatically uses the Get * utility to load the asset into the document. For example, to talk to a JSON web service on * another domain:

* *
    Ojay.HTTP.GET('http://example.com/posts/45.json', {
         *         user: 'your_username',
         *         api_key: '4567rthdtyue566w34',
         *         callback: 'handleJSON'
         *     });
         *     
         *     var handleJSON = function(json) {
         *         // process json object
         *     };
* *

If you request a URL on your own domain, Ojay will always make an Ajax request rather * than a Get-utility request. If you want to load assets from your own domain or talk to * your own web service, use Ojay.HTTP.load().

* * @param {String} url The URL to request * @param {Object} parameters Key-value pairs to be used as a query string * @param {Object} callbacks Object containing callback functions * @returns {MethodChain} */ GET: HTTP.GET.wrap(function(ajax, url, parameters, callbacks) { if (Ojay.URI.parse(url).isLocal() || !YAHOO.util.Get) return ajax(url, parameters, callbacks); this.load(url, parameters, callbacks); }), /** *

Ojay.HTTP.POST is overloaded to allow POST requests to other domains using * hidden forms and iframes. Using the same syntax as for Ajax requests to your own domain, * you can send data to any URL to like. An example:

* *
    Ojay.HTTP.POST('http://example.com/posts/create', {
         *         user: 'your_username',
         *         api_key: '4567rthdtyue566w34',
         *         title: 'A new blog post',
         *         content: 'Lorem ipsum dolor sit amet...'
         *     });
* *

Due to same-origin policy restrictions, you cannot access the response for cross- * domain POST requests, so no callbacks may be used.

* * @param {String} url The URL to request * @param {Object} parameters Key-value pairs to be used as a POST message * @param {Object} callbacks Object containing callback functions * @returns {MethodChain} */ POST: HTTP.POST.wrap(function(ajax, url, parameters, callbacks) { if (Ojay.URI.parse(url).isLocal()) return ajax(url, parameters, callbacks); this.send(url, parameters); }), /** *

Uses the YUI Get utility to load assets into the current document. Pass in the URL you * want to load, parameters for the query string, and callback functions if you need them.

* *

Ojay automatically infers which type of asset (script or stylesheet) you want to load * from the URL. If it ends in '.css', Ojay makes a stylesheet request, otherwise it loads * a script file.

* * @param {String} url The URL to request * @param {Object} parameters Key-value pairs to be used as a query string * @param {Object} callbacks Object containing callback functions */ load: function(url, parameters, callbacks) { var path = Ojay.URI.parse(url).path, assetType = determineAssetType(path), uri = Ojay.URI.build(url, parameters), callbacks = callbacks || {}; if (typeof callbacks == 'function') callbacks = {onSuccess: callbacks}; if (uri.params.jsonp && callbacks.onSuccess) { var handlerID = getHandlerId(); uri.setParam(uri.params.jsonp, handlerID); if (uri.params.jsonp !== 'jsonp') delete uri.params.jsonp; window[handlerID] = handleJsonP.partial(callbacks.onSuccess); callbacks.onSuccess = removeHandler(handlerID); } YAHOO.util.Get[assetType](uri.toString(), callbacks); }, /** *

Allows cross-domain POST requests by abstracting away the details required to implement * such a technique. An invisible form and iframe are injected into the document to send * the data you specify to the required URL. There is no way of communicating across frames * from different domains, so you cannot use any callbacks to see what happened to your data.

* * @param {String} url The URL to send data to * @param {Object} parameters Key-value pairs to be used as a POST message */ send: function(url, parameters) { var form = this._buildPostForm(url, parameters, true); createIframe(); Ojay(document.body).insert(form.node, 'top'); form.node.submit(); form.remove(); }, _buildPostForm: function(url, parameters, postToIframe) { var uri = Ojay.URI.build(url, parameters), postUrl = uri._getPathWithHost(), params = uri.params; var attributes = {action: postUrl, method: 'POST'}; if (postToIframe) attributes.target = IFRAME_NAME; return Ojay( Ojay.HTML.form(attributes, function(HTML) { for (var field in params) HTML.input({ type: 'hidden', name: field, value: String(params[field]) }); }) ).hide(); } }); HTTP.GET.redirectTo = function(url, parameters) { window.location.href = Ojay.URI.build(url, parameters).toString(); }; HTTP.POST.redirectTo = function(url, parameters) { var form = HTTP._buildPostForm(url, parameters, false).node; Ojay(document.body).insert(form, 'top'); form.submit(); }; JS.MethodChain.addMethods(HTTP); })(); /** * @constructor * @class URI */ Ojay.URI = new JS.Class('Ojay.URI', { extend: { /** * @param {String} string * @returns {String} */ sanitize: function(string) { return String(string).trim().replace('&', '&').replace('&', '&'); }, /** * @param {String} string * @returns {URI} */ parse: function(string) { if (string instanceof this) return string; var uri = new this; string = this.sanitize(string) .replace(/^(\w+)(:\/+)/, function(match, capture, keep) { uri.protocol = capture; return keep; }) .replace(/^:\/+([^\:\/]+)/, function(match, capture) { uri.domain = capture; return ''; }) .replace(/^:(\d+)/, function(match, capture) { uri.port = capture; return ''; }) .replace(/^[^\?\#]+/, function(match, capture) { uri.path = match; return ''; }) .replace(/#(.*)$/, function(match, capture) { uri.hash = capture; return ''; }); if (!uri.port) uri.port = (uri.domain == this.local.domain) ? this.local.port : this.DEFAULT_PORTS[uri.protocol]; if (uri.path.charAt(0) != '/' && uri.domain == this.local.domain) uri.path = this.local.directory + uri.path; if (/^\?/.test(string)) string.slice(1).split('&').forEach(function(pair) { var bits = pair.split('='); uri.setParam(bits[0], bits[1].replace('+', ' ')); }); return uri; }, /** * @param {String} url * @param {Object} params * @returns {URI} */ build: function(url, params) { var uri = this.parse(url), params = params || {}, value; for (var key in params) { value = (typeof params[key] == 'function') ? params[key]() : params[key]; uri.setParam(key, value); } return uri; }, /** * @param {String|URI} a * @param {String|URI} b * @returns {Boolean} */ compare: function(a,b) { return this.parse(a).equals(b); }, DEFAULT_PORTS: { http: '80', https: '443' } }, /** */ initialize: function() { this.protocol = this.klass.local.protocol; this.domain = this.klass.local.domain; this.path = ''; this.keys = []; this.params = {}; this.toString = this._toString; }, /** * @returns {String} */ _toString: function() { var string = this._getPathWithHost(), params = []; var queryString = this.getQueryString(); if (queryString.length) string += '?' + queryString; if (typeof this.hash === 'string') string += '#' + this.hash; return string; }, _getPathWithHost: function() { return this._getProtocolString() + (this.domain||'') + this._getPortString() + (this.path||''); }, /** * @returns {String} */ getQueryString: function() { return this.keys.sort().map(function(key) { return encodeURIComponent(key) + '=' + encodeURIComponent(this.params[key]); }, this).join('&'); }, /** * @returns {String} */ _getProtocolString: function() { return this.protocol ? this.protocol + '://' : ''; }, /** * @returns {String} */ _getPortString: function() { if (!this.port || this.port == this.klass.DEFAULT_PORTS[this.protocol]) return ''; return ':' + this.port; }, /** * @param {String|URI} uri * @returns {Boolean} */ equals: function(uri) { uri = this.klass.parse(uri); if (this.domain != uri.domain || this.protocol != uri.protocol || this.port != uri.port || this.path != uri.path || this.hash != uri.hash) return false; if (!this.paramsEqual(uri)) return false; return true; }, /** * @param {String} key * @param {String} value */ setParam: function(key, value) { var bits = [key, value].map(decodeURIComponent).map('trim'); if (this.keys.indexOf(bits[0]) == -1) this.keys.push(bits[0]); this.params[bits[0]] = bits[1]; }, /** * @param {String|URI} uri * @returns {Boolean} */ paramsEqual: function(uri) { uri = this.klass.parse(uri); for (var key in this.params) { if (this.params[key] != uri.params[key]) return false; } for (key in uri.params) { if (this.params[key] != uri.params[key]) return false; } return true; }, /** * @returns {Boolean} */ isLocal: function() { return this.protocol == this.klass.local.protocol && this.domain == this.klass.local.domain && this.port == this.klass.local.port; } }); Ojay.URI.extend({ local: { protocol: window.location.protocol.replace(/\W/g, ''), domain: window.location.hostname, directory: window.location.pathname.replace(/[^\/]*$/, '') } }); Ojay.URI.local.port = window.location.port || Ojay.URI.DEFAULT_PORTS[Ojay.URI.local.protocol || 'http']; JS.extend(String.prototype, { parseURI: Ojay.URI.method('parse').methodize(), equalsURI: Ojay.URI.method('compare').methodize() });_application/x-javascriptO*bplist00z{X$versionX$objectsY$archiverT$top("()0!12TUVWXYZ[\]^_`abcdefghijklmnoptuU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1&'#$%&[NS.relativeWNS.base_1https://cdn.othermedia.com/ojay/0.4.1/pkg/http.js*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#AD 3456EWNS.keysZNS.objects%789:;<=>?@ABCD FGHIJKLMNOPQRS !"#$VServerZConnectionZKeep-Alive_Content-EncodingTVary\Content-TypeWExpires]Cache-Control]Accept-Ranges_X-Ua-Compatible]Last-ModifiedWX-CacheTDate^Content-LengthVApacheZKeep-Alive_timeout=2, max=98Tgzip_Accept-Encoding,U_application/x-javascript_Fri, 08 Oct 2021 17:18:04 GMT_max-age=315360000Ubytes]IE=EmulateIE7_Thu, 25 Jun 2009 14:45:21 GMT_MISS from cdn.othermedia.com_Tue, 11 Oct 2011 17:18:04 GMTT6680*+qr_NSMutableDictionaryqs/\NSDictionary]*+vw_NSHTTPURLResponsexy/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiver|}_WebResourceResponse#-27bh"-6<?ENWY`hsu #1CQY^mt/Nnsx ~_1https://cdn.othermedia.com/ojay/0.4.1/pkg/http.jsO*/* Copyright (c) 2007-2008 the OTHER media Limited Licensed under the BSD license, http://ojay.othermedia.org/license.html Version: 0.4.1 Build: source */ (function() { JS.extend(Ojay, /** @scope Ojay */ { /** *

Returns true iff the given value is truthy and is not just whitespace.

* @param {String} value * @returns {Boolean} */ isBlank: function(value) { return value ? false : (String(value).trim() == ''); }, /** *

Returns true iff the given value is a number.

* @param {String} value * @returns {Boolean} */ isNumeric: function(value) { return this.NUMBER_FORMAT.test(String(value)); }, /** *

Returns true iff the given value is an email address.

* @param {String} value * @returns {Boolean} */ isEmailAddress: function(value) { return this.EMAIL_FORMAT.test(String(value)); }, /** *

JSON number definition from http://json.org

*/ NUMBER_FORMAT: /^\-?(0|[1-9]\d*)(\.\d+)?(e[\+\-]?\d+)?$/i, /** *

Format for valid email addresses from http://www.regular-expressions.info/email.html

*/ EMAIL_FORMAT: /^[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+(?:[A-Z]{2}|com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum)\b$/i }); Ojay.Forms = function(description) { description.call(DSL); }; // Stores all instances of styled form controls. var styledInputs = []; JS.extend(Ojay.Forms, /** @scope Ojay.Forms */{ /** *

Returns an Ojay collection wrapping the label for the given input.

* @param {String|HTMLElement|DomCollection} input * @returns {DomCollection} */ getLabel: function(input) { input = Ojay(input); if (!input.node) return Ojay(); var label = input.ancestors('label'); if (label.node) return label.at(0); var id = input.node.id; label = [].filter.call(document.getElementsByTagName('label'), function(label) { return id && label.htmlFor == id; }); return Ojay(label.slice(0,1)); }, /** *

Returns the serialization of the given form as a string.

* @param {String|HTMLElement|DomCollection} form * @returns {String} */ getQueryString: function(form) { var data = YAHOO.util.Connect.setForm(Ojay(form).node); YAHOO.util.Connect.resetFormState(); return data; }, /** *

Returns the serialization of the given form as an object.

* @param {String|HTMLElement|DomCollection} form * @returns {Object} */ getData: function(form) { return this.getQueryString(form).split('&').reduce(function(memo, pair) { var data = pair.split('=').map(decodeURIComponent).map('trim'); if (memo[data[0]] === undefined) memo[data[0]] = data[1]; return memo; }, {}); }, /** * @param {String|HTMLElement|DomCollection} * @param {String|Boolean} value */ setValue: function(element, value) { var selected, options, element = Ojay(element); switch (true) { case element.every({matches: '[type=radio]'}) : selected = element.map('node').filter({value: value})[0]; if (!selected) return; element.set({checked: false}); selected.checked = true; break; case element.matches('[type=checkbox]') : element.node.checked = !!(value === true || value == element.node.value); break; case element.matches('select') : options = Array.from(element.node.options); selected = options.filter(function(option) { return (option.value == value) || (option.text == value); })[0]; if (!selected) return; options.forEach(function(option) { option.selected = false }); selected.selected = true; break; case element.matches('input') : case element.matches('[type=hidden]') : case element.matches('textarea') : element.node.value = String(value); break; } }.curry(), /** *

Submits the given form, routing the submission through our validdation and * ajax routines.

* @param {String|HTMLElement} form */ submit: function(form) { form = Ojay(form); getForm(form.node.id)._submit(); }, /** *

Goes through all sets of form rules and makes sure each one is associated with * an existing form in the document. Useful for replacing a form dynamically and then * reattaching all the rules. Returns the number of reattached forms.

* @returns {Number} */ reattach: function() { var n = 0; for (var id in forms) { if (forms[id]._attach()) ++n; } return n; }, /** *

Makes sure all styled form inputs are displaying the right values from the * underlying form inputs.

*/ update: function() { styledInputs.forEach(function(input) { if (input.isA(Ojay.Forms.Select)) input._updateDisplayFromSelect(); else input.setChecked(); }); } }); /** *

The FormDescription class encapsulates sets of rules about how a form is to * behave. Each instance holds a set of requirements, which are tested against the form's * data each time the form is submitted in order to decide whether to allow submission to * the server.

* @constructor * @class FormDescription * @private */ var FormDescription = new JS.Class('Ojay.Forms.FormDescription', /** @scope FormDescription.prototype */{ include: JS.Observable, /** * @param {String} id */ initialize: function(id) { this._formID = id; this._displayNames = {}; this._attach(); this._requirements = {}; this._validators = []; this._dataFilters = []; this._ajaxResponders = []; this._dsl = new FormDSL(this); this._when = new WhenDSL(this); this._before = new BeforeDSL(this); }, /** *

Finds the form element in the document and hijacks its submit event. Returns a * boolean to indicate whether the form was reattached.

* @returns {Boolean} */ _attach: function() { if (this._hasForm()) return false; this._inputs = {}; this._labels = {}; this._names = {}; this._form = Ojay.byId(this._formID); if (!this._hasForm()) return false; for (var field in this._requirements) this._requirements[field]._attach(); this._form.on('submit', function(form, evnt) { if (!this._handleSubmission()) evnt.stopDefault(); }, this); return true; }, /** *

Returns true iff the description object has an associated form * element in the current document.

* @returns {Boolean} */ _hasForm: function() { return this._form && this._form.ancestors('body').node; }, /** *

Returns the FormRequirement object for the named field. If no existing * requirement object is found for the field, a new one is created for it.

* @param {String} name * @returns {FormRequirement} */ _getRequirement: function(name) { return this._requirements[name] || (this._requirements[name] = new FormRequirement(this, name)); }, /** *

Submits the form, enforcing validation and Ajax rules.

*/ _submit: function() { if (this._handleSubmission()) this._form.node.submit(); }, /** *

Processes form submission events by validating the form and stopping the event * from proceeding if the form data is found to be invalid.

*/ _handleSubmission: function() { var allowed = true; valid = this._isValid(); if (this._ajax || !valid) allowed = false; if (!this._ajax || !valid) return allowed; var form = this._form.node; Ojay.HTTP[(form.method || 'POST').toUpperCase()](form.action, this._data, { onSuccess: function(response) { this._ajaxResponders.forEach({call: [null, response]}); }.bind(this) }); return allowed; }, /** *

Returns an Ojay collection representing all the inputs in the form with the given * name.

* @param {String} name * @return {DomCollection} */ _getInputs: function(name) { if (this._inputs[name]) return this._inputs[name]; var inputs = this._form.descendants('input, textarea, select'); if (name) inputs = inputs.filter(function(element) { return element.node.name == name; }); return this._inputs[name] = inputs; }, /** *

Returns an Ojay collection for the label tag for a specified name * or element referece.

* @param {String|HTMLElement|DomCollection} name * @returns {DomCollection} */ _getLabel: function(name) { if (name.node) name = name.node; if (name.name) name = name.name; return this._labels[name] || ( this._labels[name] = Ojay.Forms.getLabel(this._getInputs(name)) ); }, /** *

Returns a human-readable name for the given field. If the developer has not specified * a name, it is inferred from the field's label, or from the field's name itself if no label * is found.

* @param {String} name * @returns {String} */ _getName: function(field) { if (this._names[field]) return this._names[field]; if (this._displayNames[field]) return this._names[field] = this._displayNames[field]; var label = this._getLabel(field); var name = ((label.node || {}).innerHTML || field).stripTags(); name = name.replace(/(\w)[_-](\w)/g, '$1 $2') .replace(/([a-z])([A-Z])/g, function(match, a, b) { return a + ' ' + b.toLowerCase(); }); return this._names[field] = name.charAt(0).toUpperCase() + name.substring(1); }, /** *

Returns the data in the form using YAHOO.util.Connect.

* @returns {Object} */ _getData: function() { return this._data = Ojay.Forms.getData(this._form); }, /** *

Validates the form by applying the set of requirements to the form's current data and * building up a collection of errors, and notifies any observers that validation has taken * place.

*/ _validate: function() { this._errors = new FormErrors(this); var data = this._getData(), key, input; this._dataFilters.forEach(function(filter) { filter(data); }); for (key in data) Ojay.Forms.setValue(this._getInputs(key), data[key]); Ojay.Forms.update(); data = new FormData(data); for (key in this._requirements) this._requirements[key]._test(data.get(key), data); this._validators.forEach(function(validate) { validate(data, this._errors); }, this); var fields = this._errors._fields(); for (key in this._inputs) [this._getInputs(key), this._getLabel(key)].forEach( it()[fields.indexOf(key) == -1 ? 'removeClass' : 'addClass']('invalid')); this.notifyObservers(this); }, /** *

Returns true iff the form's current data is valid according to the set * of stored requirements.

* @returns {Boolean} */ _isValid: function() { this._validate(); return this._errors._count() === 0; }, /** *

Causes the form's inputs and labels to add/remove the class name 'focused' in response * to user interaction, to allow you to highlight the active field with CSS.

*/ _highlightActiveField: function() { this._getInputs('').forEach(function(input) { input.on('focus').addClass('focused')._(this)._getLabel(input).addClass('focused'); input.on('blur').removeClass('focused')._(this)._getLabel(input).removeClass('focused'); }, this); } }); var isPresent = function(value) { return !Ojay.isBlank(value) || ['must not be blank']; }; /** *

The FormRequirement class encapsulates a set of tests against the value of a single * form field. The tests are defined externally and added using the _add() method. Each * test should be a function that takes a value and decides whether or not it is valid. The * FormRequirement instance can be used to run all the tests against a field.

* @constructor * @class FormRequirement * @private */ var FormRequirement = new JS.Class('Ojay.Forms.FormRequirement', { /** * @param {FormDescription} form * @param {String} field */ initialize: function(form, field) { this._form = form; this._field = field; this._tests = []; this._dsl = new RequirementDSL(this); this._attach(); }, /** */ _attach: function() { this._elements = this._form._getInputs(this._field); }, /** * @param {Function} block */ _add: function(block) { this._tests.push(block); }, /** * @param {String} value * @param {Object} data * @returns {Array|Boolean} */ _test: function(value, data) { if (!this._visible()) return true; var errors = [], tests = this._tests.length ? this._tests : [isPresent], value = value || ''; tests.forEach(function(block) { var result = block(value, data), message, field; if (result !== true) { message = result[0]; field = result[1] || this._field; this._form._errors.register(this._field); this._form._errors.add(field, message); } }, this); }, /** * @returns {Boolean} */ _visible: function() { return !!this._elements && this._elements.reduce(function(truth, element) { var node = element.node; do { if (node.parentNode && Ojay(node).getStyle('display') == 'none') return false; } while (node = node.parentNode) return truth; }, true); } }); /** *

The FormData class provides read-only access to data objects for the * purposes of validation. Validation routines cannot modify form data through this * class. To use it, pass an object to the constructor. The resulting instance will * provide a get() method to retrieve fields from the object but will not * let you write to these fields.

* @contructor * @class FormData * @private */ var FormData = new JS.Class('Ojay.Forms.FormData', /** @scope FormData.prototype */{ /** * @param {Object} data */ initialize: function(data) { this.get = function(field) { return data[field] === undefined ? null : data[field]; }; } }); /** *

The FormErrors class provides append-only access to error lists for the * purposes of validation. Validation routines cannot modify existing errors or remove * them from the list, so existing validation rules cannot be bypassed.

* @contructor * @class FormErrors * @private */ var FormErrors = new JS.Class('Ojay.Forms.FormErrors', /** @scope FormErrors.prototype */{ initialize: function(form) { var errors = {}, base = []; /** *

Creates storage space to put errors for the named field

* @param {String} field * @returns {FormErrors} */ this.register = function(field) { errors[field] = errors[field] || []; return this; }; /** *

Adds an error to the given field with message message.

* @param {String} field * @param {String} message * @returns {FormErrors} */ this.add = function(field, message) { this.register(field); if (errors[field].indexOf(message) == -1) errors[field].push(message); return this; }; /** *

Adds an error to the form as a whole rather than to an individual field.

* @param {String} message * @returns {FormErrors} */ this.addToBase = function(message) { base.push(message); return this; }; /** *

Returns the number of errors.

* @returns {Number} */ this._count = function() { var n = base.length; for (var field in errors) n += errors[field].length; return n; }; /** *

Returns an array of objects representing the errors in the form.

* @returns {Array} */ this._messages = function() { var name, messages = base.map(function(message) { return {field: null, message: message}; }); for (var field in errors) { name = form._getName(field); errors[field].forEach(function(message) { messages.push({field: field, message: name + ' ' + message}); }); } return messages; }; /** *

Returns a list of field names that currently are invalid.

* @returns {Array} */ this._fields = function() { var fields = []; for (var field in errors) fields.push(field); return fields; }; } }); /** * @overview * *

Ojay.Forms provides a DSL-style API for writing specs for validating form input, * handling errors when they occur, and allowing forms to be submitted using Ajax. Its most basic * building block is the requires statement, which expresses the fact that a given field * must contain some data in order to be valid. You write all your form specs within a block like * the following:

* *
    Ojay.Forms(function() { with(this) {
 *         
 *         // The form with id 'foo' requires field named 'bar'
 *         form('foo').requires('bar');
 *     }});
* *

Note that, although all these examples have their own Ojay.Forms() block, you could * put them all in one block together.

* *

You can also use the word expects in place of requires -- the two perform * exactly the same function. As well as simply requiring a field, you can say what form the input * should take using a variety of pre-built validator functions. Here's an example:

* *
    Ojay.Forms(function() { with(this) {
 *         
 *         form('theForm')
 *             .requires('username').toHaveLength({minimum: 6})
 *             .requires('email').toMatch(EMAIL_FORMAT)
 *             .expects('tickets').toBeNumeric();
 *     }});
* *

The full list of validator methods can be found in the RequirementDSL class. All * requirments take as their last argument an optional string specifying the text that should * be displayed in the error message if the field is invalid. Additionally, the requires * and expects methods take an optional argument to specify how the name of the field * should be presented. If no custom name is given for the field, a name is inferred from the field's * label or its name attribute.

* *
    Ojay.Forms(function() { with(this) {
 *         
 *         // Gives message "User email is not valid"
 *         form('signup').requires('userEmail').toMatch(EMAIL_FORMAT);
 *         
 *         // Gives message "Your email address is not valid"
 *         form('signup').requires('userEmail', 'Your email address').toMatch(EMAIL_FORMAT);
 *         
 *         // Gives message "User email is not a valid email address"
 *         form('signup').requires('userEmail').toMatch(EMAIL_FORMAT, 'is not a valid email address');
 *     }});
* *

You can add your own custom validation routines using the validates method. In * your validation callback, you have access to the form's data and its error list. You can * read from the data and add errors as follows:

* *
    Ojay.Forms(function() { with(this) {
 *         
 *         form('purchase').validates(function(data, errors) {
 *             
 *             // Check a field and add error to that field
 *             if (data.get('ccNumber').length != 16)
 *                 errors.add('ccNumber', 'is not a valid credit card number');
 *             
 *             // Check two fields and add error to the form
 *             // rather than to a specific field
 *             if (data.get('start') > data.get('end'))
 *                 errors.addToBase('Start date must be before end date');
 *         });
 *     }});
* *

Once you've set up all your rules you'll want to do something with the errors. This * is where the helper function when comes in. when is used to set up * responses to events, and can handle validation events. In the example below, the callback * is passed an array of errors, each of which has a field property that says which * input name it belongs to (null if it was added using addToBase) and a * message field that contains the full text of the error message.

* *
    Ojay.Forms(function() { with(this) {
 *         
 *         when('purchase').isValidated(function(errors) {
 *             errors.forEach(function(error) {
 *                 Ojay('#someElement').insert(error.message, 'top');
 *             });
 *         });
 *         
 *         // Ojay provides a pre-build error handler that lists the
 *         // errors in the element you specify:
 *         when('purchase').isValidated(displayErrorsIn('#error-list'));
 *     }});
* *

Finally, the DSL allows you specify that a form submits using Ajax. To use this * feature, you just need to tell Ojay what to do with the server response. For example:

* *
    Ojay.Forms(function() { with(this) {
 *         
 *         form('login').submitsUsingAjax();
 *         
 *         when('login').responseArrives(function(response) {
 *             Ojay('#response').setContent(response.responseText);
 *         });
 *         
 *         // Or use Ojay's pre-built display method:
 *         when('login').responseArrives(displayResponseIn('#response'));
 *     }});
*/ // Store to hold sets of form rules, entry per page form. var forms = {}; /** *

Returns the FormDescription for the given id. A new description is * created if one does not already exist for the id.

* @param {String} id * @returns {FormDescription} * @private */ var getForm = function(id) { return forms[id] || (forms[id] = new FormDescription(id)); }; /** *

This is the main DSL object for Ojay.Forms. It contains methods that should * act as top-level functions in the DSL. Do not put a method in here unless it needs to be * a top-level function.

* @private */ var DSL = { /** *

Returns a DSL object for describing the form with the given id.

* @param {String} id * @returns {FormDSL} */ form: function(id) { return getForm(id)._dsl || null; }, /** *

Returns a DSL object for handling events related to the form with the * given id.

* @param {String} id * @returns {WhenDSL} */ when: function(id) { return getForm(id)._when || null; }, /** *

Returns a DSL object for applying pre-processing filters before events take place.

* @param {String} id * @returns {BeforeDSL} */ before: function(id) { return getForm(id)._before || null; }, /** *

Returns a helper function for use with when().isValidated(). The returned * function will display the forms elements as a bulleted list inside the element you * supply, in a div with the class name error-explanation.

* @param {String|HTMLElement|DomCollection} element * @returns {Function} */ displayErrorsIn: function(element) { return function(errors) { element = element.setContent ? element : Ojay(element); var n = errors.length; if (n == 0) return element.setContent(''); var were = (n == 1) ? 'was' : 'were', s = (n == 1) ? '' : 's'; element.setContent(Ojay.HTML.div({className: 'error-explanation'}, function(HTML) { HTML.p('There ' + were + ' ' + n + ' error' + s + ' with the form:'); HTML.ul(function(HTML) { errors.map('message').forEach(HTML.method('li')); }); })); }; }, /** *

Returns a helper function for use with when().responseArrives(). The returned * function will take the HTTP response body and display it in the specified element.

* @param {String|HTMLElement|DomCollection} element * @returns {Function} */ displayResponseIn: function(element) { return function(response) { response.insertInto(element); }; }, EMAIL_FORMAT: Ojay.EMAIL_FORMAT }; /** *

The FormDSL class creates DSL objects used to describe forms. Every * FormDescription instance has one of these objects that provides DSL-level * access to the description.

* @constructor * @class FormDSL * @private */ var FormDSL = new JS.Class('Ojay.Forms.FormDSL', /** @scope FormDSL.prototype */{ /** * @param {FormDescription} form */ initialize: function(form) { this._form = form; }, /** *

Returns a RequirementDSL object used to specify the requirement.

* @param {String} name * @param {String} displayed * @returns {RequirementDSL} */ requires: function(name, displayed) { var requirement = this._form._getRequirement(name); if (displayed) this._form._displayNames[name] = displayed; return requirement._dsl; }, /** *

Adds a validator function to the form that allows the user to inspect the data * and add new errors.

* @param {Function} block * @returns {FormDSL} */ validates: function(block) { this._form._validators.push(block); return this; }, /** *

Causes form submissions to be sent using Ajax rather than page-reloading requests.

* @param {Object} options * @returns {FormDSL} */ submitsUsingAjax: function(options) { this._form._ajax = true; return this; }, /** *

Causes the form to indicate which field in currently focused by applying a class * name to the focused input element.

* @returns {FormDSL} */ highlightsActiveField: function() { this._form._highlightActiveField(); return this; } }); FormDSL.include({expects: FormDSL.prototype.requires}); var FormDSLMethods = ['requires', 'expects', 'validates', 'submitsUsingAjax', 'highlightsActiveField']; /** *

The RequirementDSL class creates DSL objects used to describe form requirements. * All FormRequirement objects have one of these objects associated with them.

* @constructor * @class RequirementDSL * @private */ var RequirementDSL = new JS.Class('Ojay.Forms.RequirementDSL', /** @scope RequirementDSL.prototype */{ /** * @param {FormRequirement} requirement */ initialize: function(requirement) { this._requirement = requirement; }, /** *

Specifies that the given checkbox field must be checked.

* @param {String} message * @returns {RequirementDSL} */ toBeChecked: function(message) { var requirement = this._requirement; this._requirement._add(function(value) { var element = requirement._elements.node; return (value == element.value && element.checked) || [message || 'must be checked']; }); return this; }, /** *

Specifies that the required field must be a number in order to be considered valid.

* @param {String} message * @returns {RequirementDSL} */ toBeNumeric: function(message) { this._requirement._add(function(value) { return Ojay.isNumeric(value) || [message || 'must be a number']; }); return this; }, /** *

Specifies that the required field must have one of the values in the given list in * order to be considered valid.

* @param {Array} list * @param {String} message * @returns {RequirementDSL} */ toBeOneOf: function(list, message) { this._requirement._add(function(value) { return list.indexOf(value) != -1 || [message || 'is not valid']; }); return this; }, /** *

Specifies that the required field must have none of the values in the given list in * order to be considered valid.

* @param {Array} list * @param {String} message * @returns {RequirementDSL} */ toBeNoneOf: function(list, message) { this._requirement._add(function(value) { return list.indexOf(value) == -1 || [message || 'is not valid']; }); return this; }, /** *

Specifies that the required field must not be blank in order to be considered valid. * Calling this method is only necessary if you want a custom message for the rule, otherwise * a simple requires() will do.

* @param {String} message * @returns {RequirementDSL} */ toBePresent: function(message) { this._requirement._add(function(value) { return !Ojay.isBlank(value) || [message || 'must not be blank']; }); return this; }, /** *

Specifies that the required field must confirm the value in another field.

* @param {String} field * @param {String} message * @returns {RequirementDSL} */ toConfirm: function(field, message) { this._requirement._add(function(value, data) { return value == data.get(field) || [message || 'must be confirmed', field]; }); return this; }, /** *

Specifies that the required field must have a certain length in order to be considered * valid. Valid inputs are a number (to specify an exact length), or an object with * minimum and maximum fields.

* @param {Number|Object} options * @param {String} message * @returns {RequirementDSL} */ toHaveLength: function(options, message) { var min = options.minimum, max = options.maximum; this._requirement._add(function(value) { return (typeof options == 'number' && value.length != options && [message || 'must contain exactly ' + options + ' characters']) || (min !== undefined && value.length < min && [message || 'must contain at least ' + min + ' characters']) || (max !== undefined && value.length > max && [message || 'must contain no more than ' + max + ' characters']) || true; }); return this; }, /** *

Specifies that the required field must have a certain value in order to be considered * valid. Input should be an object with minimum and maximum fields.

* @param {Object} options * @param {String} message * @returns {RequirementDSL} */ toHaveValue: function(options, message) { var min = options.minimum, max = options.maximum; this._requirement._add(function(value) { if (!Ojay.isNumeric(value)) return [message || 'must be a number']; value = Number(value); return (min !== undefined && value < min && [message || 'must be at least ' + min]) || (max !== undefined && value > max && [message || 'must not be greater than ' + max]) || true; }); return this; }, /** *

Specifies that the required field must match a given regex in order to be considered * valid.

* @param {Regexp} format * @param {String} message * @returns {RequirementDSL} */ toMatch: function(format, message) { this._requirement._add(function(value) { return format.test(value) || [message || 'is not valid']; }); return this; } }); RequirementDSL.include(FormDSLMethods.reduce(function(memo, method) { memo[method] = function() { var base = this._requirement._form._dsl; return base[method].apply(base, arguments); }; return memo; }, {})); /** *

The WhenDSL class creates DSL objects used to describe form requirements. All * FormDescription objects have one of these objects associated with them. The WhenDSL * is used specifically to describe events linked to forms.

* @constructor * @class WhenDSL * @private */ var WhenDSL = new JS.Class('Ojay.Forms.WhenDSL', /** @scope WhenDSL.prototype */{ /** * @param {FormDescription} form */ initialize: function(form) { this._form = form; }, /** *

Allows a hook to be registered to say what should be done with the list of error * messages when a particular form is validated.

* @param {Function} block * @param {Object} context */ isValidated: function(block, context) { this._form.subscribe(function(form) { block.call(context || null, form._errors._messages()); }); }, /** *

Registers a function to handle the HTTP response when an Ajax form submission completes.

* @param {Function} block * @param {Object} context */ responseArrives: function(block, context) { block = Function.from(block); if (context) block = block.bind(context); this._form._ajaxResponders.push(block); } }); /** *

The BeforeDSL class creates DSL objects used to describe pre-processing actions. All * FormDescription objects have one of these objects associated with them.

* @constructor * @class BeforeDSL * @private */ var BeforeDSL = new JS.Class('Ojay.Forms.BeforeDSL', { /** * @param {FormDescription} form */ initialize: function(form) { this._form = form; }, /** * @param {Function} block */ isValidated: function(block) { this._form._dataFilters.push(block); } }); /** *

The Inputable module is mixed into Forms.Select, and indirectly into * Forms.Checkbox and Forms.RadioButtons.Item through Checkable. * It provides methods for setting class names on form elements to indicate the hovered, focused * and disabled states of form inputs.

* @module Inputable * @private */ var Inputable = new JS.Module('Ojay.Forms.Inputable', /** @scope Inputable */{ include: Ojay.Observable, extend: { DEFAULT_WRAPPER_POSITION: 'relative' }, /** *

Called inside class constructors to set up the behaviour of the form input and * its associated label. Hides the input off the page, and sets up a set of events to * enable class names to be changed.

*/ _setupInput: function() { var wrapper = Ojay( Ojay.HTML.span() ).setStyle({position: this._options.wrapperPosition || Inputable.DEFAULT_WRAPPER_POSITION}); this._input.insert(wrapper.node, 'before'); wrapper.insert(this._input.node, 'bottom'); this._input.setStyle({position: 'absolute', left: '-5000px', top: 0}); this._input.on('focus')._(this).setFocused(true); this._input.on('blur')._(this).setFocused(false); this._label = Ojay.Forms.getLabel(this._input); if (this._label.node) this._label.addClass(this._inputType); this._interface = [this._input, this._label]; if (this.getHTML) this._interface.push(this.getHTML()); this._interface.forEach(it().on('mouseover')._(this).setHovered(true)); this._interface.forEach(it().on('mouseout')._(this).setHovered(false)); this._interface.forEach(it().addClass('js')); this.setDisabled(); }, /** *

Adds or removes the class name 'focused' from the input and its label depending on state.

* @param {Boolean} state * @returns {Inputable} */ setFocused: function(state) { if (this._input.node.checked) this.setChecked(); this._setClass(state, 'focused'); return this; }, /** *

Adds or removes the class name 'focused' from the input and its label depending on state.

* @param {Boolean} state * @returns {Inputable} */ setHovered: function(state) { this._setClass(state, 'hovered'); return this; }, /** *

Adds or removes the class name 'disabled' from the input and its label depending on state.

* @param {Boolean} state * @returns {Inputable} */ setDisabled: function(state) { this.disabled = (state === undefined) ? this._input.node.disabled : !!state; this._input.node.disabled = this.disabled; this._setClass(this.disabled, 'disabled'); return this; }, /** *

Adds or removes a class name from the input's elements according to its state.

* @param {Boolean} state * @param {String} name */ _setClass: function(state, name) { this._stateClasses = this._stateClasses || []; if (state) { if (this._stateClasses.indexOf(name) == -1) this._stateClasses.push(name); this._stateClasses.sort(); } else { this._stateClasses = this._stateClasses.filter(function(s) { return s != name }); } this._interface.forEach(it()[state ? 'addClass' : 'removeClass'](name)); var classes = this._interface[0].node.className.split(/\s+/); var type = this._inputType, pattern = new RegExp('^' + type + '-'); var stateClass = classes.filter({match: pattern})[0]; if (stateClass) this._interface.forEach({removeClass: stateClass}); if (this._stateClasses.length) this._interface.forEach({addClass: type + '-' + this._stateClasses.join('-')}); } }); /** *

The Checkable module extends Inputable by providing methods to * handle checking and unchecking of form elements. It is used by the Forms.Checkbox * and Forms.RadioButtons.Item classes to add and remove class names from their * associated label tags.

* @private * @module Checkable */ var Checkable = new JS.Module('Ojay.Forms.Checkable', /** @scope Checkable */{ include: Inputable, /** *

Called inside class constructors to set up the behaviour of a form input and its label. * Causes the input and its label to add/remove the 'checked' class name to indicate the state * of the input.

*/ _setupButton: function() { this._setupInput(); this._input.on('click')._(this).setChecked()._(this._input.node).focus(); this.setChecked(); }, /** *

Adds or removes the class name 'checked' from the input and its label depending on whether the * input is checked. If the input is part of a RadioButtons group, notifies the group in * order to change the state of the currently checked input.

* @param {Boolean} state * @param {Boolean} notify * @returns {Checkable} */ setChecked: function(state, notify) { var oldChecked = !!this.checked; this.checked = (state === undefined) ? this._input.node.checked : !!state; if (this._group) { if (this.checked) { this._input.node.checked = true; this._group._check(this, notify); } } else { this._input.node.checked = this.checked; if (notify !== false && oldChecked != this.checked) this.notifyObservers('change'); } this._setClass(this.checked, 'checked'); return this; }, /** *

Returns true iff the element is checked.

* @returns {Boolean} */ isChecked: function() { return !!this.checked; } }); JS.MethodChain.addMethod('focus'); /** *

The Forms.RadioButtons class can be used to 'hijack' sets of radio buttons to * make them easier to style using CSS. The radio inputs themselves become hidden (they are positioned * off-screen rather than hidden using display or visibility) and their labels * have their class names changed to mirror changes to the inputs as the user interacts with the form.

* *

This class is designed as a light-weight and unobtrusive replacement for YAHOO.widget.ButtonGroup * for the simple case where you want to style your form inputs and retain programmatic access to them. * It encourages accessible markup through use of label elements, and does not alter the HTML * structure of your form in any way.

* * @constructor * @class Forms.RadioButtons */ Ojay.Forms.RadioButtons = new JS.Class('Ojay.Forms.RadioButtons', /** @scope Forms.RadioButtons.prototype */{ include: Ojay.Observable, /** * @param {String|HTMLElement|DomCollection} inputs * @param {Object} options */ initialize: function(inputs, options) { this._items = Ojay(inputs).map(function(input) { return new this.klass.Item(this, input, options); }, this); if (this._items.map('_input.node.name').unique().length > 1) throw new Error('Attempt to create a RadioButtons object with radios of different names'); this._checkedItem = this._items.filter('checked')[0] || null; }, /** *

This method is used to make sure that only one input appears checked at any time. Items * must notify their group when they become checked so the group can uncheck the previously * checked item.

* @param {Forms.RadioButtons.Item} item * @param {Boolean} notify */ _check: function(item, notify) { var current = this._checkedItem; if (current && current != item) current.setChecked(false); if (notify !== false && current != item) this.notifyObservers('change'); this._checkedItem = item; }, /** *

Returns the Item in the RadioButtons group with the given id or value.

* @param {String|Number} id * @returns {Forms.RadioButtons.Item} */ getItem: function(id) { return this._items.filter(function(item) { return item._input.node.id == id || item._input.node.value == id; })[0]; }, /** * @returns {DomCollection} */ getInput: function() { return Ojay(this._items.map('_input.node')); }, /** * @returns {DomCollection} */ getLabel: function() { return Ojay(this._items.map('_label.node')); }, /** *

Returns the current value of the radio button group.

* @returns {String} */ getValue: function() { var item = this._items.filter('_input.node.checked')[0]; return item ? item._input.node.value : null; }, /** *

Sets the value of the radio button group to the given value, if a button * with that value exists.

* @param {String} value * @param {Boolean} notify * @returns {Forms.RadioButtons} */ setValue: function(value, notify) { var input = this.getItem(value); if (input) input.setChecked(true, notify); return this; }, extend: /** @scope Forms.RadioButtons */{ /** * @constructor * @class Forms.RadioButtons.Item */ Item: new JS.Class('Ojay.Forms.RadioButtons.Item', /** @scope Forms.RadioButtons.Item.prototype */{ include: Checkable, _inputType: 'radio', /** * @param {Forms.RadioButtons} group * @param {DomCollection} input * @param {Object} options */ initialize: function(group, input, options) { this._options = options || {}; styledInputs.push(this); if (!input || !input.node || input.node.type != 'radio') throw new TypeError('Attempt to create a RadioButtons object with non-radio element'); this._group = group; this._input = input; this._setupButton(); } }) } }); /** *

The Forms.Checkbox class can be used to 'hijack' checkbox inputs in HTML forms to * make them easier to style using CSS. The checkbox inputs themselves become hidden (they are positioned * off-screen rather than hidden using display or visibility) and their labels * have their class names changed to mirror changes to the inputs as the user interacts with the form.

* *

This class is designed as a light-weight and unobtrusive replacement for YAHOO.widget.Button * for the simple case where you want to style your form inputs and retain programmatic access to them. * It encourages accessible markup through use of label elements, and does not alter the HTML * structure of your form in any way.

* * @constructor * @class Forms.Checkbox */ Ojay.Forms.Checkbox = new JS.Class('Ojay.Forms.Checkbox', /* @scope Forms.Checkbox.prototype */{ include: Checkable, _inputType: 'checkbox', /** * @param {String|HTMLElement|DomCollection} input * @param {Object} options */ initialize: function(input, options) { this._options = options || {}; styledInputs.push(this); this._input = Ojay(input); if (!this._input || !this._input.node || this._input.node.type != 'checkbox') throw new TypeError('Attempt to create a Checkbox object with non-checkbox element'); this._setupButton(); }, /** * @returns {DomCollection} */ getInput: function() { return this._input; }, /** * @returns {DomCollection} */ getLabel: function() { return this._label; } }); Ojay.Forms.Checkbox.include({ getValue: Ojay.Forms.Checkbox.prototype.isChecked, setValue: Ojay.Forms.Checkbox.prototype.setChecked }); /** *

The Forms.Select class can be used to 'hijack' drop-down menu inputs in HTML forms to * make them easier to style using CSS. The select inputs themselves become hidden (they are positioned * off-screen rather than hidden using display or visibility) and their labels * have their class names changed to mirror changes to the inputs as the user interacts with the form.

* *

This class is designed as a light-weight and unobtrusive replacement for YAHOO.widget.Button * for the simple case where you want to style your form inputs and retain programmatic access to them. * It encourages accessible markup through use of label elements, and does not alter the HTML * structure of your form in any way.

* * @constructor * @class Forms.Select */ Ojay.Forms.Select = new JS.Class('Ojay.Forms.Select', /** @scope Forms.Select.prototype */{ include: [JS.State, Inputable], _inputType: 'select', extend: /** @scope Forms.Select */{ CONTAINER_CLASS: 'select-container', DISPLAY_CLASS: 'select-display', BUTTON_CLASS: 'select-button', LIST_CLASS: 'select-list', /** * @constructor * @class Forms.Select.Option */ Option: new JS.Class('Ojay.Forms.Select.Option', /** @scope Forms.Select.Option.prototype */{ /** * @param {Forms.Select} select * @param {HTMLElement} option */ initialize: function(select, option) { this._select = select; this._option = Ojay(option); this.value = option.value || ''; this._label = option.text.stripTags(); this.hovered = false; var element = this.getHTML(); [element.on('mouseover'), element.on('mousemove')] .forEach(it()._(this).setHovered(true)); }, /** *

Returns an Ojay collection wrapping the list item used to display the option.

* @returns {DomCollection} */ getHTML: function() { if (this._html) return this._html; return this._html = Ojay( Ojay.HTML.li(this._label) ); }, /** *

Sets the option to be hovered, and notified its parent Select instance * so it can un-hover the currently hovered option.

* @param {Boolean} state * @returns {Forms.Select.Option} */ setHovered: function(state) { this.hovered = (state !== false); if (this.hovered) { this._select._setHoveredOption(this); this._nudgeIntoView(); } this.getHTML()[state === false ? 'removeClass' : 'addClass']('hovered'); return this; }, /** *

Makes sure the option is in view if the list container has a fixed height * and is using overflow: scroll.

*/ _nudgeIntoView: function() { var list = this._select._elements._listContainer; var listRegion = list.getRegion(), myRegion = this.getHTML().getRegion(); if (listRegion.contains(myRegion)) return; var scroll = list.node.scrollTop || 0, edge = (myRegion.top > listRegion.top) ? 'bottom' : 'top'; list.node.scrollTop = scroll + myRegion[edge] - listRegion[edge]; } }) }, /** * @param {String|HTMLElement|DomCollection} select * @param {Object} options */ initialize: function(select, options) { this._options = options || {}; styledInputs.push(this); this._input = Ojay(select); if (!this._input || this._input.node.tagName.toLowerCase() != 'select') throw new TypeError('Attempt to create a Select object with non-select element'); var elements = this._elements = {}; this._input.insert(this.getHTML().node, 'after'); this._setupInput(); this.updateOptions(); this.setState('LIST_OPEN'); this.hideList(false); this._input.on('blur')._(this).hideList(true); // Wait a little bit because 'keydown' fires before the value changes [this._input.on('keydown'), this._input.on('change')] .forEach(it().wait(0.001)._(this)._updateDisplayFromSelect(false)); this._input.on('keydown', function(element, evnt) { var code = evnt.keyCode || 0; if (code.between(48,57) || code.between(65,90) || code.between(37,40)) this.wait(0.001).showList(); }, this); elements._container.setStyle({position: 'relative', cursor: 'default'}); [elements._display, elements._button].forEach(it().on('click')._(this).toggleList()); var KeyListener = YAHOO.util.KeyListener; new KeyListener(this._input.node, {keys: KeyListener.KEY.ESCAPE}, { fn: this.method('hideList').partial(false) }).enable(); new KeyListener(this._input.node, {keys: KeyListener.KEY.ENTER}, { fn: this.method('hideList').partial(true) }).enable(); elements._listContainer.setStyle({position: 'absolute'}); }, /** *

Returns an Ojay collection wrapping the HTML used as a stand-in for the * select input.

* @returns {DomCollection} */ getHTML: function() { var elements = this._elements, klass = this.klass; if (elements._container) return elements._container; return elements._container = Ojay( Ojay.HTML.div({className: this.klass.CONTAINER_CLASS}, function(HTML) { elements._display = Ojay( HTML.div({className: klass.DISPLAY_CLASS}) ); elements._button = Ojay( HTML.div({className: klass.BUTTON_CLASS}) ); elements._listContainer = Ojay( HTML.div({className: klass.LIST_CLASS}, function(HTML) { elements._list = Ojay( HTML.ul() ); }) ); }) ); }, /** * @returns {DomCollection} */ getInput: function() { return this._input; }, /** * @returns {DomCollection} */ getLabel: function() { return this._label; }, /** *

Focuses the select element.

* @returns {Forms.Select} */ _focusInput: function() { this._input.node.focus(); }, /** *

Refreshes the list of displayed options. Use this method if you change the * contents of the select element.

* @returns {Forms.Select} */ updateOptions: function() { this._elements._list.setContent(''); this._options = Array.from(this._input.node.options).map(function(option) { option = new this.klass.Option(this, option); this._elements._list.insert(option.getHTML().node); return option; }, this); this._updateDisplayFromSelect(); return this; }, /** *

Updates the UI of the instance in response to the current state of the * underlying select input.

* @param {Boolean} notify */ _updateDisplayFromSelect: function(notify) { var oldValue = this._currentValue; var selected = this.getSelectedOption(); if (!selected) return; this._elements._display.setContent(selected.text.stripTags()); this._getOption(selected.value).setHovered(true); if (this.inState('LIST_OPEN') || notify === false) return; this._currentValue = selected.value; if (oldValue !== undefined && oldValue != this._currentValue) this.notifyObservers('change'); }, /** *

Returns the Select.Option instance with the given value.

* @param {String} value * @returns {Forms.Select.Option} */ _getOption: function(value) { return this._options.filter({value: value})[0] || null; }, /** *

Sets the given Select.Option to be hovered, and removes hover state from * all other options.

* @param {Forms.Select.Option} */ _setHoveredOption: function(option) { if (this._currentOption) this._currentOption.setHovered(false); this._currentOption = option; }, /** *

Returns an array of references to option elements.

* @returns {Array} */ _getOptions: function() { return Array.from(this._input.node.options); }, /** *

Returns a reference to the currently selected option element, or a * reference to the first element if none is selected.

* @returns {HTMLElement} */ getSelectedOption: function() { return this._getOptions().filter('selected')[0] || this._input.node.options[0] || null; }, /** *

Returns all the option elements in the select whose value equals * the supplied value.

* @param {String|Number} value * @returns {Array} */ getOptionsByValue: function(value) { return this._getOptions().filter({value: value}); }, /** *

Returns the current value of the select element.

* @returns {String} */ getValue: function() { return this.getSelectedOption().value; }, /** *

Sets the value of the select element to the given value, triggering * a change event unless you pass false as the second parameter.

* @param {String|Number} value * @param {Boolean} notify * @returns {Forms.Select} */ setValue: function(value, notify) { Ojay.Forms.setValue(this._input, value); this._updateDisplayFromSelect(notify); return this; }, /** *

Sets the position of the list relative to the container so the two are properly aligned.

* @returns {Forms.Select} */ updateListPosition: function() { var region = this._elements._container.getRegion(); if (!region) return this; var list = this._elements._listContainer; list.setStyle({width: region.getWidth() + 'px', left: 0, top: region.getHeight() + 'px'}); return this; }, states: { LIST_CLOSED: /** @scope Forms.Select.prototype */{ /** *

Displays the drop-down list.

* @returns {Forms.Select} */ showList: function() { if (this.disabled) return this; this.updateListPosition(); this._elements._listContainer.show(); this.setState('LIST_OPEN'); this._focusInput(); var selected = this.getSelectedOption(); if (selected) this._getOption(selected.value).setHovered(true); return this; }, /** *

Displays the drop-down list.

* @returns {Forms.Select} */ toggleList: function() { return this.showList(); } }, LIST_OPEN: /** @scope Forms.Select.prototype */{ /** *

Hides the drop-down list.

* @param {Boolean} update * @returns {Forms.Select} */ hideList: function(update) { this._elements._listContainer.hide(); this.setState('LIST_CLOSED'); if (update !== false) { this.setValue(this._currentOption.value); this._focusInput(); } return this; }, /** *

Hides the drop-down list.

* @param {Boolean} update * @returns {Forms.Select} */ toggleList: function(update) { return this.hideList(update); } } } }); })();_application/x-javascriptO,bplist00z{X$versionX$objectsY$archiverT$top("()0!12TUVWXYZ[\]^_`abcdefghijklmnoptuU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1&'#$%&[NS.relativeWNS.base_2https://cdn.othermedia.com/ojay/0.4.1/pkg/forms.js*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#AD%3456EWNS.keysZNS.objects%789:;<=>?@ABCD FGHIJKLMNOPQRS !"#$VServerZConnectionZKeep-Alive_Content-EncodingTVary\Content-TypeWExpires]Cache-Control]Accept-Ranges_X-Ua-Compatible]Last-ModifiedWX-CacheTDate^Content-LengthVApacheZKeep-Alive_timeout=2, max=99Tgzip_Accept-Encoding,U_application/x-javascript_Fri, 08 Oct 2021 17:18:04 GMT_max-age=315360000Ubytes]IE=EmulateIE7_Thu, 25 Jun 2009 14:45:21 GMT_MISS from cdn.othermedia.com_Tue, 11 Oct 2011 17:18:04 GMTU13628*+qr_NSMutableDictionaryqs/\NSDictionary**+vw_NSHTTPURLResponsexy/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiver|}_WebResourceResponse#-27bh#.7=@FOXZaitv$2DRZ_nu0Oouz~_2https://cdn.othermedia.com/ojay/0.4.1/pkg/forms.jsO3/* Copyright (c) 2007-2008 the OTHER media Limited Licensed under the BSD license, http://ojay.othermedia.org/license.html Version: 0.4.1 Build: source */ /** *

Accordion implements the well-known accordion menu widget. It allows for both * horizontal and vertical collapse directions, and allows the animation to be configured. Like * all Ojay widgets, it comes with a set of events that you can use to couple an accordion * instance to other parts of your application.

* *

Creating an accordion is straightforward. Start with a list of elements, each of which * should contain an element that you want to collapse. For example:

* *
    <div class="section">
 *         <h3>Section 1</h3>
 *         <p>Lorem ipsum...</p>
 *     </div>
 *     <div class="section">
 *         <h3>Section 2</h3>
 *         <p>Dolor sit amet...</p>
 *     </div>
 *     <div class="section">
 *         <h3>Section 3</h3>
 *         <p>Quaniam omnes...</p>
 *     </div>
* *

In this example, the paragraphs will collapse and the headings will be the menu tabs. * The following script sets up the menu:

* *
    var acc = new Ojay.Accordion('horizontal',
 *             '.section', 'p');
* *

This will make a few changes to the markup, which you'll need to be aware of in order * to apply CSS. After the script runs, the document will look like this:

* *
    <div class="section accordion-section">
 *         <h3>Section 1</h3>
 *     </div>
 *     <div class="accordion-collapsible">
 *         <p>Lorem ipsum...</p>
 *     </div>
 *     <div class="section accordion-section">
 *         <h3>Section 2</h3>
 *     </div>
 *     <div class="accordion-collapsible">
 *         <p>Dolor sit amet...</p>
 *     </div>
 *     <div class="section accordion-section">
 *         <h3>Section 3</h3>
 *     </div>
 *     <div class="accordion-collapsible">
 *         <p>Quaniam omnes...</p>
 *     </div>
* *

The original sections get an additional class to indicate that they're part of an * Accordion instance, and the collapsible elements get placed inside a new wrapper * element, outside their original parent. This seems a little odd but is required to work * around a layout bug in WebKit.

* @constructor * @class Accordion */ Ojay.Accordion = new JS.Class('Ojay.Accordion', /** @scope Ojay.Accordion.prototype */{ include: Ojay.Observable, extend: /** @scope Ojay.Accordion */{ DIRECTIONS: { horizontal: 'HorizontalSection', vertical: 'VerticalSection' } }, /** * @param {String} direction * @param {HTMLElement|String} sections * @param {String} collapsible * @param {Object} options */ initialize: function(direction, sections, collapsible, options) { this._options = options || {}; this._direction = direction; this._sections = sections; this._collapsible = collapsible; }, /** * @returns {Accordion} */ setup: function() { var SectionClass = this.klass[this.klass.DIRECTIONS[this._direction]]; this._sections = Ojay(this._sections).map(function(section, index) { var section = new SectionClass(this, index, section, this._collapsible, this._options); section.on('expand')._(this).notifyObservers('sectionexpand', index, section); section.on('collapse')._(this).notifyObservers('sectioncollapse', index, section); return section; }, this); var state = this.getInitialState(); this._sections[state.section].expand(false); return this; }, /** * @returns {Object} */ getInitialState: function() { return {section: 0}; }, /** * @param {Object} state * @returns {Accordion} */ changeState: function(state) { this._sections[state.section].expand(); return this; }, /** * @param {Accordion.Section} section * @param {Boolean} animate */ _expand: function(section, animate) { if (this._currentSection) this._currentSection.collapse(animate); this._currentSection = section; }, /** * @returns {Array} */ getSections: function() { return this._sections.slice(); }, /** * @param {Number} n * @param {Boolean} animate * @returns {Accordion} */ expand: function(n, animate) { var section = this._sections[n]; if (section) section.expand(animate); return this; }, /** * @param {Number} n * @param {Boolean} animate * @returns {Accordion} */ collapse: function(n, animate) { var section = this._sections[n]; if (section) section.collapse(animate); return this; } }); Ojay.Accordion.extend(/** @scope Ojay.Accordion */{ /** *

The Accordion.Section class models a single collapsible section within an * accordion menu. Only one section of an accordion may be open at any time. Ojay supports * both vertical and horizontal accordions; these have different methods for size calculations * and are implemented as subclasses. This class should be considered abstract.

* @constructor * @class Accordion.Section */ Section: new JS.Class('Ojay.Accordion.Section', /** @scope Ojay.Accordion.Section.prototype */{ include: Ojay.Observable, extend: /** @scope Ojay.Accordion.Section */{ SECTION_CLASS: 'accordion-section', COLLAPSER_CLASS: 'accordion-collapsible', DEFAULT_EVENT: 'click', DEFAULT_DURATION: 0.4, DEFAULT_EASING: 'easeBoth' }, /** *

To instantiate a section, pass in an Accordion instance, the section's * container element, and an element within the container that should be collapsible. * The final argument sets configuration options, passed through from the Accordion * constructor.

* @param {Accordion} accordion * @param {Number} index * @param {DomCollection} element * @param {String} collapsible * @param {Object} options */ initialize: function(accordion, index, element, collapsible, options) { this._accordion = accordion; this._element = element; // Restructure the HTML - wrap the collapsing element with a div for resizing, // and move the collapsing element outside its original parent (workaround for // WebKit layout bug affecting horizontal menus). var target = element.descendants(collapsible).at(0); this._collapser = Ojay( Ojay.HTML.div({className: this.klass.COLLAPSER_CLASS}) ); target.insert(this._collapser, 'before'); this._collapser.insert(target); this._element.insert(this._collapser, 'after'); // Fixes some layout issues in IE this._collapser.setStyle({position: 'relative', zoom: 1}); options = options || {}; this._duration = options.duration || this.klass.DEFAULT_DURATION; this._easing = options.easing || this.klass.DEFAULT_EASING; this._element.addClass(this.klass.SECTION_CLASS); this._element.on(options.event || this.klass.DEFAULT_EVENT)._(this._accordion).changeState({section: index}); if (options.collapseOnClick) this._element.on('click', function() { if (this._open) this.collapse(); }, this); this._open = true; this.collapse(false); }, /** *

Returns a reference to the outer container element for the section. This element * acts as the click target for toggling visibility.

* @returns {DomCollection} */ getContainer: function() { return this._element; }, /** *

Returns a reference to the element that collapses, hiding its content.

* @returns {DomCollection} */ getCollapser: function() { return this._collapser; }, /** *

Causes the section to collapse. Pass the parameter false to prevent * animation.

* @param {Boolean} animate * @returns {Accordion.Section} */ collapse: function(animate) { if (!this._open) return this; this._collapser.setStyle({overflow: 'hidden'}); this._element.removeClass('expanded').addClass('collapsed'); var settings = {}; settings[this.param] = (animate === false) ? 0 : {to: 0}; var acc = this._accordion; if (animate !== false ) this.notifyObservers('collapse'); if (animate === false) { this._collapser.setStyle(settings).setStyle({overflow: 'hidden'}); this._open = false; return this; } else { return this._collapser.animate(settings, this._duration, {easing: this._easing}) .setStyle({overflow: 'hidden'}) ._(function(self) { self._open = false; }, this) ._(this); } }, /** *

Causes the section to expand. Pass the parameter false to prevent * animation. Any section in the same accordion that is currently open will collapse.

* @param {Boolean} animate * @returns {Accordion.Section} */ expand: function(animate) { if (this._open) return this; this._accordion._expand(this, animate); this._collapser.setStyle({overflow: 'hidden'}); this._element.addClass('expanded').removeClass('collapsed'); var size = this.getSize(), settings = {}, postAnim = {overflow: ''}; settings[this.param] = (animate === false) ? '' : {to: size}; postAnim[this.param] = ''; var acc = this._accordion; if (animate !== false ) this.notifyObservers('expand'); if (animate === false) { this._collapser.setStyle(settings).setStyle({overflow: ''}); this._open = true; return this; } else { return this._collapser.animate(settings, this._duration, {easing: this._easing}) .setStyle(postAnim) ._(function(self) { self._open = true; }, this) ._(this); } } }) }); Ojay.Accordion.extend(/** @scope Ojay.Accordion */{ /** * @constructor * @class Ojay.Accordion.HorizontalSection */ HorizontalSection: new JS.Class('Ojay.Accordion.HorizontalSection', Ojay.Accordion.Section, /** @scope Ojay.Accordion.HorizontalSection.prototype */{ param: 'width', /** *

Returns the width of the section at full expansion.

* @returns {Number} */ getSize: function() { var sections = this._accordion.getSections(); var sizes = sections.map(function(section) { var collapser = section._collapser, size = collapser.getRegion().getWidth(); collapser.setStyle({width: section == this ? '' : 0}); return size; }, this); var size = this._collapser.getRegion().getWidth(); sections.forEach(function(section, i) { section._collapser.setStyle({width: sizes[i] + 'px'}); }); return size; } }), /** * @constructor * @class Ojay.Accordion.VerticalSection */ VerticalSection: new JS.Class('Ojay.Accordion.VerticalSection', Ojay.Accordion.Section, /** @scope Ojay.Accordion.VerticalSection.prototype */{ param: 'height', /** *

Returns the height of the section at full expansion.

* @returns {Number} */ getSize: function() { if (!this._open) this._collapser.setStyle({height: ''}); var size = this._collapser.getRegion().getHeight(); if (!this._open) this._collapser.setStyle({height: 0}); return size; } }) });_application/x-javascriptO/bplist00z{X$versionX$objectsY$archiverT$top("()0!12TUVWXYZ[\]^_`abcdefghijklmnoptuU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1&'#$%&[NS.relativeWNS.base_6https://cdn.othermedia.com/ojay/0.4.1/pkg/accordion.js*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#AD3456EWNS.keysZNS.objects%789:;<=>?@ABCD FGHIJKLMNOPQRS !"#$VServerZConnectionZKeep-Alive_Content-EncodingTVary\Content-TypeWExpires]Cache-Control]Accept-Ranges_X-Ua-Compatible]Last-ModifiedWX-CacheTDate^Content-LengthVApacheZKeep-Alive_timeout=2, max=99Tgzip_Accept-Encoding,U_application/x-javascript_Fri, 08 Oct 2021 17:18:04 GMT_max-age=315360000Ubytes]IE=EmulateIE7_Thu, 25 Jun 2009 14:45:21 GMT_MISS from cdn.othermedia.com_Tue, 11 Oct 2011 17:18:04 GMTT3212*+qr_NSMutableDictionaryqs/\NSDictionary3*+vw_NSHTTPURLResponsexy/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiver|}_WebResourceResponse#-27bh"'2;ADJS\^emxz(6HV^cry4Ssx}~_6https://cdn.othermedia.com/ojay/0.4.1/pkg/accordion.jsO dOjay.Overlay.on('show')._('body').addClass('overlay-open'); Ojay.Overlay.on('hide')._('body').removeClass('overlay-open'); Ojay.onDOMReady(function() { Ojay('a').forEach(function(link) { link.node.hideFocus = true; if (link.hasClass('new-window')) { link.node.target = '_blank'; var title = link.node.title; link.node.title = title ? title + ' (Opens in a new window)' : 'This link opens in a new window'; } }); if (/iPhone/i.test(navigator.userAgent)) return; var mask = new Ojay.PageMask({color: '#E7ECEF', opacity: 0.8}); var overlay = new Ojay.ContentOverlay({width: 880}); mask.positionBehind(overlay); var closeButton = Ojay( Ojay.HTML.div({className: 'close-button'}, 'Close') ); closeButton.on('click')._(overlay).hide('fade')._(mask).hide('fade'); overlay.getContainer().insert(closeButton, 'top'); Ojay('.popup').on('click', function(link, evnt) { evnt.stopDefault(); Ojay.HTTP.GET(link.node.href) .insertInto(overlay) .evalScripts() ._(mask).show('fade') ._(overlay).fitToContent().center().show('fade') }); }); setupTabbedPaginators = function(list, section) { var registry = Ojay(list).map(function(el) { return new Ojay.Paginator(el, { rows: 1, columns: 1, direction: 'horizontal' }); }); var tabs = new Ojay.Tabs(section); tabs.setup(); var update = function(p) { var Paginator = registry[p-1]; if (!Paginator) return; Paginator.wait(Ojay.Tabs.SWITCH_TIME + 0.3).setup().addControls('after'); registry[p-1] = null; }; tabs.on('pagechange', function(tabs, p) { update(p); }); update(1); }; openLoginOverlay = function(overlayLink) { (function() { if (/iPhone/i.test(navigator.userAgent)) return; var mask = new Ojay.PageMask({color: '#E7ECEF', opacity: 0.8}); var overlay = new Ojay.ContentOverlay({width: 880}); mask.positionBehind(overlay); var closeButton = Ojay( Ojay.HTML.div({className: 'close-button'}, 'Close') ); closeButton.on('click')._(overlay).hide('fade')._(mask).hide('fade'); overlay.getContainer().insert(closeButton, 'top'); var region = null; Ojay(overlayLink).on('click', function(link, evnt) { evnt.stopDefault(); Ojay.HTTP.GET(link.node.href) .insertInto(overlay) .evalScripts() ._(mask).show('fade') ._(overlay).fitToContent().center().show('fade')._(function() { region = overlay.getRegion(); }); }); // To accomodate changing section sizes setInterval(function() { overlay.fitToContent(); if (region) overlay.setPosition(region.left, region.top); }, 500); })(); };_application/x-javascriptObplist00noX$versionX$objectsY$archiverT$top""()0!12NOPQRSTUVWXYZ[\]^_`abcdhiU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1 !#$%&[NS.relativeWNS.base_Bhttps://www.imperialcollegeunion.org/data/static/site/js/global.js*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#AD)3456BWNS.keysZNS.objects789:;<=>?@A CDEFGHIJKLMVServer]Accept-RangesZConnection\Content-TypeTDate]Last-Modified^Content-Length_Content-EncodingTVaryTEtagZKeep-AliveVApacheUbytesZKeep-Alive_application/x-javascript_Tue, 11 Oct 2011 17:18:04 GMT_Fri, 30 Sep 2011 13:41:44 GMTT1030Tgzip_Accept-Encoding_"1768006-b64-4ae28c92df600"_timeout=15, max=98*+ef_NSMutableDictionaryeg/\NSDictionary d*+jk_NSHTTPURLResponselm/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiverpq_WebResourceResponse#-27\b}(-8AGJPYbdks~&+0;BHSn),1EI]k}r_Bhttps://www.imperialcollegeunion.org/data/static/site/js/global.jsO,var NewsTabSection = new JS.Class({ include: JS.State, extend: { Story: new JS.Class({ initialize: function(section, element) { this._section = section; this._element = Ojay(element); var find = this._element.method('descendants'); this._headline = find('h3').node.innerHTML.stripTags(); this._image = find('img'); }, select: function(state) { if (state) this._section.getStories().forEach({select: false}); this.getElement()[state ? 'show' : 'hide'](); this.getImageContainer()[state ? 'addClass' : 'removeClass']('selected'); }, getElement: function() { return this._element; }, getHeadline: function() { return this._headline; }, getImage: function() { if (this._dupImage) return this._dupImage; var img = this._image.node, w = Number(img.width), h = Number(img.height); var f = 100 / w; return this._dupImage = Ojay( Ojay.HTML.img({src: img.src, width: f*w, height: f*h, title: img.title}) ); }, getImageContainer: function() { return this._imageContainer || null; }, extend: { STORY_SELECTOR: '.picture-story', extract: function(element, section) { return Ojay(element).descendants(this.STORY_SELECTOR).map(function(element) { return new this(section, element); }, this); } } }), Controller: new JS.Class({ initialize: function(section) { this._section = section; section.getStories().forEach(function(story, i) { story.getImage().on('click')._(section).setStory(i+1); }, this); this._elements = {}; }, getHTML: function() { if (this._elements._container) return this._elements._container; var container = this._elements._container = Ojay( Ojay.HTML.div() ); this._section.getStories().forEach(function(story) { var element = story._imageContainer = Ojay( Ojay.HTML.div({className: 'img'}) ); var clipper = Ojay( Ojay.HTML.div() ); clipper.insert(story.getImage().node); element.insert(clipper.node); container.insert(element.node); }); container.addClass('news-photos'); return this._elements._container = container; } }) }, initialize: function(container) { this._selector = container; this.setState('CREATED'); }, getInitialState: function() { return {story: 1}; }, changeState: function(state) { if (state.story !== undefined) this._handleSetStory(state.story); }, getStories: function() { return this._stories || null; }, getController: function() { return this._controller || null; }, states: { CREATED: { setup: function() { this._container = Ojay(this._selector); if (!this._container.node) return this; this._stories = this.klass.Story.extract(this._container, this); this._controller = new this.klass.Controller(this); this._container.insert(this._controller.getHTML().node, 'top'); this.setState('READY'); var state = this.getInitialState(); this._handleSetStory(state.story); return this; } }, READY: { setStory: function(n) { n = Number(n); if (n == this._currentStory || n < 1 || n > this._stories.length) return; this.changeState({story: n}); return this; }, _handleSetStory: function(n) { this._stories[n-1].select(true); } }, SWITCHING: {} } });_application/x-javascriptObplist00noX$versionX$objectsY$archiverT$top""()0!12NOPQRSTUVWXYZ[\]^_`abcdhiU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1 !#$%&[NS.relativeWNS.base_Lhttps://www.imperialcollegeunion.org/data/static/site/js/news-tab-section.js*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#AD3456BWNS.keysZNS.objects789:;<=>?@A CDEFGHIJKLMVServer]Accept-RangesZConnection\Content-TypeTDate]Last-Modified^Content-Length_Content-EncodingTVaryTEtagZKeep-AliveVApacheUbytesZKeep-Alive_application/x-javascript_Tue, 11 Oct 2011 17:18:04 GMT_Fri, 30 Sep 2011 13:41:44 GMTT1142Tgzip_Accept-Encoding_"176800a-112c-4ae28c92df600"_timeout=15, max=97*+ef_NSMutableDictionaryeg/\NSDictionary,*+jk_NSHTTPURLResponselm/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiverpq_WebResourceResponse#-27\b}27BKQTZclnu}05:ELR]x #'47<PThvr_Lhttps://www.imperialcollegeunion.org/data/static/site/js/news-tab-section.jsO // This library is maintained at // http://github.com/othermedia/flickr Flickr={Client:new JS.Class({initialize:function(a){this._key=a||Flickr.API_KEY},call:function(a,c,b,d){a=/^flickr\./.test(a)?a:'flickr.'+a;c=JS.extend({method:a,api_key:this._key},c||{});Flickr.JSONP.request(Flickr.REST_ENDPOINT,c,b,d)},feed:function(a,c,b,d){a=/\.gne$/.test(a)?a:a+'.gne';Flickr.JSONP.request(Flickr.FEED_ENDPOINT+a,c,b,d)},groupBrowse:function(a,c,b){this.call('groups.browse',{cat_id:a},c,b)},groupInfo:function(a,c,b){this.call('groups.getInfo',{group_id:a},c,b)},groupDiscuss:function(a,c,b){this.feed('groups_discuss',{id:a},c,b)},groupPool:function(a,c,b){this.feed('groups_pool',{id:a},c,b)},photoFavourites:function(a,c,b){this.feed('photos_faves',{id:a},c,b)},getGroupPhotos:function(c,b,d){var f=this._wrapPhotos;this.groupPool(c,function(a){b.call(d,f(a))})},getFavourites:function(c,b,d){var f=this._wrapPhotos;this.photoFavourites(c,function(a){b.call(d,f(a))})},_wrapPhotos:function(a){var c=[];for(var b=0,d=a.items.length;b?@A CDEFGHIJKLMVServer]Accept-RangesZConnection\Content-TypeTDate]Last-Modified^Content-Length_Content-EncodingTVaryTEtagZKeep-AliveVApacheUbytesZKeep-Alive_application/x-javascript_Tue, 11 Oct 2011 17:18:04 GMT_Fri, 30 Sep 2011 13:41:44 GMTT1100Tgzip_Accept-Encoding_"1768004-98f-4ae28c92df600"_timeout=15, max=96*+ef_NSMutableDictionaryeg/\NSDictionary *+jk_NSHTTPURLResponselm/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiverpq_WebResourceResponse#-27\b}(-8AGJPYbdks~&+0;BHSn),1EI]k}r_Bhttps://www.imperialcollegeunion.org/data/static/site/js/flickr.jsOFlickrViewer = new JS.Class({ include: Ojay.Observable, initialize: function(apiKey, groupId) { this._flickr = new Flickr.Client(apiKey); this._ready = false; this._flickr.getFavourites(groupId, function(photos) { this._photos = photos; this._ready = true; this.notifyObservers('ready'); }, this) }, getHTML: function() { if (!this._ready) return null; if (this._html) return this._html; var self = this; this._html = Ojay( Ojay.HTML.div(function(h) { self._photoDisplay = h.div(function(h) { self._photos.forEach(function(photo) { h.div({className: 'photo'}, h.a({ href: photo.getLink() }, h.img({ src: photo.getThumbnail() }) ) ); }); }); self._descriptionDisplay = Ojay( h.div({className: 'description'}) ); }) ); this._pager = new Ojay.Paginator(this._photoDisplay, { direction: 'horizontal', rows: 1, columns: 1, looping: true }); this._pager.on('pagechange', function(pager, p) { this._updateDescription(p); }, this); return this._html; }, setup: function() { if (!this._ready || this._setup) return; var x = Math.max(Math.ceil(Math.random() * this._photos.length), 1); this._pager.setPage(x); this._setup = true; this._pager.setup(); this._pager.addControls('before'); this._updateDescription(this._pager.getCurrentPage()); }, _updateDescription: function(p) { var desc = this._photos[p-1].getDescription().replace(/^(\s*

.*?<\/p>){2}/i, ''); this._descriptionDisplay.setContent(desc); } }); _application/x-javascriptObplist00noX$versionX$objectsY$archiverT$top""()0!12NOPQRSTUVWXYZ[\]^_`abcdhiU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1 !#$%&[NS.relativeWNS.base_Ihttps://www.imperialcollegeunion.org/data/static/site/js/flickr-viewer.js*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#AD3456BWNS.keysZNS.objects789:;<=>?@A CDEFGHIJKLMVServer]Accept-RangesZConnection\Content-TypeTDate]Last-Modified^Content-Length_Content-EncodingTVaryTEtagZKeep-AliveVApacheUbytesZKeep-Alive_application/x-javascript_Tue, 11 Oct 2011 17:18:04 GMT_Fri, 30 Sep 2011 13:41:44 GMTS692Tgzip_Accept-Encoding_"1768003-611-4ae28c92df600"_timeout=15, max=99*+ef_NSMutableDictionaryeg/\NSDictionary*+jk_NSHTTPURLResponselm/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiverpq_WebResourceResponse#-27\b}/4?HNQW`ikrz -27BIOZu"/27KOcqr_Ihttps://www.imperialcollegeunion.org/data/static/site/js/flickr-viewer.jsO{(function(){var g=void 0,h=null,aa=encodeURIComponent,ba=decodeURIComponent,j=Math;function ca(a,b){return a.name=b}var k="push",da="slice",ea="replace",fa="load",l="charAt",ga="value",n="indexOf",ha="match",o="name",ia="host",r="toString",s="length",t="prototype",u="split",v="stopPropagation",ja="scope",w="location",x="getString",y="substring",la="navigator",A="join",B="toLowerCase",C;function ma(a,b){switch(b){case 0:return""+a;case 1:return a*1;case 2:return!!a;case 3:return a*1E3}return a}function D(a){return g==a||"-"==a||""==a}function na(a){if(!a||""==a)return"";for(;a&&" \n\r\t"[n](a[l](0))>-1;)a=a[y](1);for(;a&&" \n\r\t"[n](a[l](a[s]-1))>-1;)a=a[y](0,a[s]-1);return a}function oa(a){var b=1,c=0,d;if(!D(a)){b=0;for(d=a[s]-1;d>=0;d--)c=a.charCodeAt(d),b=(b<<6&268435455)+c+(c<<14),c=b&266338304,b=c!=0?b^c>>21:b}return b}function pa(){return j.round(j.random()*2147483647)} function qa(){}function E(a,b){return aa instanceof Function?b?encodeURI(a):aa(a):(F(68),escape(a))}function G(a){a=a[u]("+")[A](" ");if(ba instanceof Function)try{return ba(a)}catch(b){F(17)}else F(68);return unescape(a)}var ra=function(a,b,c,d){a.addEventListener?a.addEventListener(b,c,!!d):a.attachEvent&&a.attachEvent("on"+b,c)},sa=function(a,b,c,d){a.removeEventListener?a.removeEventListener(b,c,!!d):a.detachEvent&&a.detachEvent("on"+b,c)};function H(a){return a&&a[s]>0?a[0]:""} function ta(a){var b=a?a[s]:0;return b>0?a[b-1]:""}var ua=function(){this.prefix="ga.";this.F={}};ua[t].set=function(a,b){this.F[this.prefix+a]=b};ua[t].get=function(a){return this.F[this.prefix+a]};ua[t].contains=function(a){return this.get(a)!==g};function va(a){a[n]("www.")==0&&(a=a[y](4));return a[B]()}function wa(a,b){var c,d={url:a,protocol:"http",host:"",path:"",c:new ua,anchor:""};if(!a)return d;c=a[n]("://");if(c>=0)d.protocol=a[y](0,c),a=a[y](c+3);c=a.search("/|\\?|#");if(c>=0)d.host=a[y](0,c)[B](),a=a[y](c);else return d.host=a[B](),d;c=a[n]("#");if(c>=0)d.anchor=a[y](c+1),a=a[y](0,c);c=a[n]("?");c>=0&&(xa(d.c,a[y](c+1)),a=a[y](0,c));d.anchor&&b&&xa(d.c,d.anchor);a&&a[l](0)=="/"&&(a=a[y](1));d.path=a;return d} function xa(a,b){function c(b,c){a.contains(b)||a.set(b,[]);a.get(b)[k](c)}for(var d=na(b)[u]("&"),e=0;e=1||(a=["utmt=error","type="+a,"utmwv=5.1.7","utmn="+pa(),"utmsp=1"],b&&a[k]("api="+b),c&&a[k]("msg="+E(c[y](0,100))),J.p&&a[k]("aip=1"),Aa(a[A]("&")))};var Ba=0;function K(a){return(a?"_":"")+Ba++} var Ca=K(),Da=K(),Ea=K(),Fa=K(),Ga=K(),L=K(),M=K(),Ha=K(),Ia=K(),Ja=K(),Ka=K(),La=K(),Ma=K(),Na=K(),Oa=K(),Pa=K(),Qa=K(),Ra=K(),Sa=K(),Ta=K(),Ua=K(),Va=K(),Wa=K(),Xa=K(),Ya=K(),Za=K(),$a=K(),ab=K(),bb=K(),cb=K(),db=K(),eb=K(),fb=K(),gb=K(),hb=K(),N=K(!0),ib=K(),jb=K(),kb=K(),lb=K(),mb=K(),nb=K(),ob=K(),pb=K(),qb=K(),rb=K(),O=K(!0),sb=K(!0),tb=K(!0),ub=K(!0),wb=K(!0),xb=K(!0),yb=K(!0),zb=K(!0),Ab=K(!0),Bb=K(!0),Cb=K(!0),P=K(!0),Db=K(!0),Eb=K(!0),Fb=K(!0),Gb=K(!0),Hb=K(!0),Ib=K(!0),Jb=K(!0),Kb=K(!0), Lb=K(!0),Mb=K(!0),Nb=K(!0),Ob=K(!0),Pb=K(!0),Qb=K(),Rb=K();K();var Sb=K(),Tb=K(),Ub=K(),Vb=K(),Wb=K(),Xb=K(),$b=K(),ac=K(),bc=K();K();var cc=K(),dc=K();var ec=function(){function a(a,c,d){Q(R[t],a,c,d)}S("_getName",Ea,58);S("_getAccount",Ca,64);S("_visitCode",O,54);S("_getClientInfo",Na,53,1);S("_getDetectTitle",Qa,56,1);S("_getDetectFlash",Oa,65,1);S("_getLocalGifPath",$a,57);S("_getServiceMode",ab,59);T("_setClientInfo",Na,66,2);T("_setAccount",Ca,3);T("_setNamespace",Da,48);T("_setAllowLinker",Ka,11,2);T("_setDetectFlash",Oa,61,2);T("_setDetectTitle",Qa,62,2);T("_setLocalGifPath",$a,46,0);T("_setLocalServerMode",ab,92,g,0);T("_setRemoteServerMode", ab,63,g,1);T("_setLocalRemoteServerMode",ab,47,g,2);T("_setSampleRate",Za,45,1);T("_setCampaignTrack",Pa,36,2);T("_setAllowAnchor",La,7,2);T("_setCampNameKey",Sa,41);T("_setCampContentKey",Xa,38);T("_setCampIdKey",Ra,39);T("_setCampMediumKey",Va,40);T("_setCampNOKey",Ya,42);T("_setCampSourceKey",Ua,43);T("_setCampTermKey",Wa,44);T("_setCampCIdKey",Ta,37);T("_setCookiePath",M,9,0);T("_setMaxCustomVariables",bb,0,1);T("_setVisitorCookieTimeout",Ha,28,1);T("_setSessionCookieTimeout",Ia,26,1);T("_setCampaignCookieTimeout", Ja,29,1);T("_setReferrerOverride",kb,49);a("_trackPageview",R[t].ka,1);a("_trackEvent",R[t].u,4);a("_trackSocial",R[t].la,104);a("_trackPageLoadTime",R[t].ja,100);a("_trackTrans",R[t].ma,18);a("_sendXEvent",R[t].t,78);a("_createEventTracker",R[t].S,74);a("_getVersion",R[t].X,60);a("_setDomainName",R[t].s,6);a("_setAllowHash",R[t].ba,8);a("_getLinkerUrl",R[t].W,52);a("_link",R[t].link,101);a("_linkByPost",R[t].aa,102);a("_setTrans",R[t].ea,20);a("_addTrans",R[t].L,21);a("_addItem",R[t].J,19);a("_setTransactionDelim", R[t].fa,82);a("_setCustomVar",R[t].ca,10);a("_deleteCustomVar",R[t].U,35);a("_getVisitorCustomVar",R[t].Y,50);a("_setXKey",R[t].ha,83);a("_setXValue",R[t].ia,84);a("_getXKey",R[t].Z,76);a("_getXValue",R[t].$,77);a("_clearXKey",R[t].P,72);a("_clearXValue",R[t].Q,73);a("_createXObj",R[t].T,75);a("_addIgnoredOrganic",R[t].H,15);a("_clearIgnoredOrganic",R[t].M,97);a("_addIgnoredRef",R[t].I,31);a("_clearIgnoredRef",R[t].N,32);a("_addOrganic",R[t].K,14);a("_clearOrganic",R[t].O,70);a("_cookiePathCopy", R[t].R,30);a("_get",R[t].V,106);a("_set",R[t].da,107);a("_addEventListener",R[t].addEventListener,108);a("_removeEventListener",R[t].removeEventListener,109);a("_initData",R[t].l,2);a("_setVar",R[t].ga,22);T("_setSessionTimeout",Ia,27,3);T("_setCookieTimeout",Ja,25,3);T("_setCookiePersistence",Ha,24,1);a("_setAutoTrackOutbound",qa,79);a("_setTrackOutboundSubdomains",qa,81);a("_setHrefExamineLimit",qa,80)},Q=function(a,b,c,d){a[b]=function(){try{return F(d),c.apply(this,arguments)}catch(a){throw za("exc", b,a&&a[o]),a;}}},S=function(a,b,c,d){R[t][a]=function(){try{return F(c),ma(this.a.get(b),d)}catch(e){throw za("exc",a,e&&e[o]),e;}}},T=function(a,b,c,d,e){R[t][a]=function(f){try{F(c),e==g?this.a.set(b,ma(f,d)):this.a.set(b,e)}catch(i){throw za("exc",a,i&&i[o]),i;}}},fc=function(a,b){return{type:b,target:a,stopPropagation:function(){throw"aborted";}}};var gc=function(a,b){return b!=="/"?!1:(a[n]("www.google.")==0||a[n](".google.")==0||a[n]("google.")==0)&&!(a[n]("google.org")>-1)?!0:!1},hc=function(a){var b=a.get(Ga),c=a[x](M,"/");gc(b,c)&&a[v]()};var lc=function(){var a={},b={},c=new ic;this.g=function(a,b){c.add(a,b)};var d=new ic;this.d=function(a,b){d.add(a,b)};var e=!1,f=!1,i=!0;this.G=function(){e=!0};this.f=function(a){this[fa]();this.set(Qb,a,!0);e=!1;d.execute(this);e=!0;b={};this.i()};this.load=function(){e&&(e=!1,this.na(),jc(this),f||(f=!0,c.execute(this),kc(this),jc(this)),e=!0)};this.i=function(){if(e)if(f)e=!1,kc(this),e=!0;else this[fa]()};this.get=function(c){c&&c[l](0)=="_"&&this[fa]();return b[c]!==g?b[c]:a[c]};this.set= function(c,d,e){c&&c[l](0)=="_"&&this[fa]();e?b[c]=d:a[c]=d;c&&c[l](0)=="_"&&this.i()};this.m=function(b){a[b]=this.b(b,0)+1};this.b=function(a,b){var c=this.get(a);return c==g||c===""?b:c*1};this.getString=function(a,b){var c=this.get(a);return c==g?b:c+""};this.na=function(){if(i){var b=this[x](Ga,""),c=this[x](M,"/");gc(b,c)||(a[L]=a[Ma]&&b!=""?oa(b):1,i=!1)}}};lc[t].stopPropagation=function(){throw"aborted";};function mc(a,b){for(var b=b||[],c=0;c=0&&d>0&&e>0&&f>0&&b>=0))return F(110),!1;a.set(O,c);a.set(wb,d);a.set(xb,e);a.set(yb,f);a.set(zb,b);return!0},pc=function(a){var b=a.get(O),c=a.get(wb),d=a.get(xb),e=a.get(yb),f=a.b(zb,1);b==g?F(113):b==NaN&&F(114);b>=0&&c>0&&d>0&&e>0&&f>=0||F(115);return[a.b(L,1),b!=g?b:"-",c||"-",d||"-",e||"-",f][A](".")},qc=function(a){return[a.b(L,1),a.b(Cb,0),a.b(P,1), a.b(Db,0)][A](".")},rc=function(a,b,c){var c=c?"":a[x](L,"1"),d=b[u](".");if(d[s]!==4||nc(d[0],c))d=h;a.set(Cb,d?d[1]*1:0);a.set(P,d?d[2]*1:10);a.set(Db,d?d[3]*1:a.get(Fa));return d!=h||!nc(b,c)},sc=function(a,b){var c=E(a[x](tb,"")),d=[],e=a.get(N);if(!b&&e){for(var f=0;f0&&(c+="|"+d[A](","))}return c?a.b(L,1)+"."+c:h},tc=function(a,b,c){c=c?"":a[x](L,"1");b=b[u](".");if(b[s]<2||nc(b[0],c))return!1;b=b[da](1)[A](".")[u]("|"); b[s]>0&&a.set(tb,G(b[0]));if(b[s]<=1)return!0;for(var c=b[1][u](b[1][n](",")==-1?"^":","),d=0;d=0&&F(125);return!0},vc=function(a,b){var c=uc(a,b);return c?[a.b(L,1),a.b(Eb,0),a.b(Fb,1),a.b(Gb,1),c][A]("."):""},uc=function(a){function b(b,e){if(!D(a.get(b))){var f=a[x](b,""),f=f[u](" ")[A]("%20"),f=f[u]("+")[A]("%20");c[k](e+"="+f)}}var c=[];b(Ib,"utmcid");b(Mb,"utmcsr");b(Kb, "utmgclid");b(Lb,"utmdclid");b(Jb,"utmccn");b(Nb,"utmcmd");b(Ob,"utmctr");b(Pb,"utmcct");return c[A]("|")},xc=function(a,b,c){c=c?"":a[x](L,"1");b=b[u](".");if(b[s]<5||nc(b[0],c))return a.set(Eb,g),a.set(Fb,g),a.set(Gb,g),a.set(Ib,g),a.set(Jb,g),a.set(Mb,g),a.set(Nb,g),a.set(Ob,g),a.set(Pb,g),a.set(Kb,g),a.set(Lb,g),!1;a.set(Eb,b[1]*1);a.set(Fb,b[2]*1);a.set(Gb,b[3]*1);wc(a,b[da](4)[A]("."));return!0},wc=function(a,b){function c(a){return(a=b[ha](a+"=(.*?)(?:\\|utm|$)"))&&a[s]==2?a[1]:g}function d(b, c){c&&(c=e?G(c):c[u]("%20")[A](" "),a.set(b,c))}b[n]("=")==-1&&(b=G(b));var e=c("utmcvr")=="2";d(Ib,c("utmcid"));d(Jb,c("utmccn"));d(Mb,c("utmcsr"));d(Nb,c("utmcmd"));d(Ob,c("utmctr"));d(Pb,c("utmcct"));d(Kb,c("utmgclid"));d(Lb,c("utmdclid"))},nc=function(a,b){return b?a!=b:!/^\d+$/.test(a)};var ic=function(){this.r=[]};ic[t].add=function(a,b){this.r[k]({name:a,xa:b})};ic[t].execute=function(a){try{for(var b=0;b=a.get(Za)*100&&a[v]()}function zc(a){Ac()&&a[v]()}function Bc(a){I[w].protocol=="file:"&&a[v]()}function Cc(a){a.get(jb)||a.set(jb,I.title,!0);a.get(ib)||a.set(ib,I[w].pathname+I[w].search,!0)};var Dc=new function(){var a=[];this.set=function(b){a[b]=!0};this.ya=function(){for(var b=[],c=0;c=0){b=b[ea](/\n|\r/g," ");f=0;for(var i=b[s];f2E3&&(b=b[y](0, 2E3),F(69));a=a+"="+b+"; path="+c+"; ";e&&(a+="expires="+(new Date((new Date).getTime()+e)).toGMTString()+"; ");d&&(a+="domain="+d+";");I.cookie=a}};var Fc,Gc,Hc=function(){if(!Fc){var a={},b=U[la],c=U.screen;a.D=c?c.width+"x"+c.height:"-";a.C=c?c.colorDepth+"-bit":"-";a.language=(b&&(b.language||b.browserLanguage)||"-")[B]();a.javaEnabled=b&&b.javaEnabled()?1:0;a.characterSet=I.characterSet||I.charset||"-";Fc=a}},Ic=function(){Hc();for(var a=Fc,b=U[la],a=b.appName+b.version+a.language+b.platform+b.userAgent+a.javaEnabled+a.D+a.C+(I.cookie?I.cookie:"")+(I.referrer?I.referrer:""),b=a[s],c=U.history[s];c>0;)a+=c--^b++;return oa(a)},Jc=function(a){Hc(); var b=Fc;a.set(mb,b.D);a.set(nb,b.C);a.set(qb,b.language);a.set(rb,b.characterSet);a.set(ob,b.javaEnabled);if(a.get(Na)&&a.get(Oa)){if(!(b=Gc)){var c,d,e;d="ShockwaveFlash";if((b=(b=U[la])?b.plugins:g)&&b[s]>0)for(c=0;c-1&&(e=d.description[u]("Shockwave Flash ")[1]);else{d=d+"."+d;try{c=new ActiveXObject(d+".7"),e=c.GetVariable("$version")}catch(f){}if(!e)try{c=new ActiveXObject(d+".6"),e="WIN 6,0,21,0",c.AllowScriptAccess="always",e=c.GetVariable("$version")}catch(i){}if(!e)try{c= new ActiveXObject(d),e=c.GetVariable("$version")}catch(m){}e&&(e=e[u](" ")[1][u](","),e=e[0]+"."+e[1]+" r"+e[2])}b=e?e:"-"}Gc=b;a.set(pb,Gc)}else a.set(pb,"-")};var X=function(){Q(X[t],"push",X[t][k],5);Q(X[t],"_createAsyncTracker",X[t].va,33);Q(X[t],"_getAsyncTracker",X[t].wa,34);this.q=0};X[t].va=function(a,b){return J.k(a,b||"")};X[t].wa=function(a){return J.o(a)};X[t].push=function(a){this.q>0&&F(105);this.q++;for(var b=arguments,c=0,d=0;d0&&(e=f[y](0,i),f=f[y](i+1));var m=e=="_gat"?J:e=="_gaq"?Kc:J.o(e);m[f].apply(m,b[d][da](1))}}catch(p){c++}this.q--;return c};var Nc=function(){function a(a,b,c,d){g==f[a]&&(f[a]={});g==f[a][b]&&(f[a][b]=[]);f[a][b][c]=d}function b(a,b,c){if(g!=f[a]&&g!=f[a][b])return f[a][b][c]}function c(a,b){if(g!=f[a]&&g!=f[a][b]){f[a][b]=g;var c=!0,d;for(d=0;d0)&&(W("__utmd","1",a[x](M,"/"),a[x](Ga,""),1E4),V("__utmd")[s]==0&&a[v]())};var Yc=function(a){a.get(O)==g?Wc(a):a.get(ub)&&!a.get(cc)?Wc(a):a.get(Bb)&&Xc(a)},Zc=function(a){a.get(Hb)&&!a.get(Ab)&&(Xc(a),a.set(Fb,a.get(zb)))},Wc=function(a){var b=a.get(Fa);a.set(sb,!0);a.set(O,pa()^Ic(a)&2147483647);a.set(tb,"");a.set(wb,b);a.set(xb,b);a.set(yb,b);a.set(zb,1);a.set(Ab,!0);a.set(Cb,0);a.set(P,10);a.set(Db,b);a.set(N,[]);a.set(ub,!1);a.set(Bb,!1)},Xc=function(a){a.set(xb,a.get(yb));a.set(yb,a.get(Fa));a.m(zb);a.set(Ab,!0);a.set(Cb,0);a.set(P,10);a.set(Db,a.get(Fa));a.set(Bb, !1)};var $c="daum:q,eniro:search_word,naver:query,pchome:q,images.google:q,google:q,yahoo:p,yahoo:q,msn:q,bing:q,aol:query,aol:q,lycos:query,ask:q,netscape:query,cnn:query,about:terms,mamma:q,voila:rdata,virgilio:qs,live:q,baidu:wd,alice:qs,yandex:text,najdi:q,seznam:q,search:q,wp:szukaj,onet:qt,szukacz:q,yam:k,kvasir:q,ozu:q,terra:query,rambler:query".split(","),fd=function(a){if(a.get(Pa)&&!a.get(cc)){for(var b=!D(a.get(Ib))||!D(a.get(Mb))||!D(a.get(Kb))||!D(a.get(Lb)),c={},d=0;d=0)||c&&c[ia][n]("google")>-1&&c.c.contains("q")&&c.path=="cse")return!1;if((b=gd(a,c))&&!b[2])return dd(a,g,b[0],g,g,"(organic)","organic",b[1],g),!0; else if(b)return!1;if(a.get(Ab))a:{for(var b=a.get(eb),d=va(c[ia]),e=0;e-1){a=!1;break a}dd(a,g,d,g,g,"(referral)","referral",g,"/"+c.path);a=!0}else a=!1;return a},gd=function(a,b){for(var c=a.get(cb),d=0;d-1){var f=H(b.c.get(e[1]));if(f&&(!e[3]||b.url[n](e[3])>-1)){a:{for(var c=f,d=a.get(db),c=G(c)[B](),i=0;i0&&d==c}var e=!1;if(d(Kb)||d(Lb))e=!0;for(var f=0;f0&&(c=b[y](e),b=b[y](0,e)),f<0?b+"?"+d+c:b+"&"+d+c)};var md="|",od=function(a,b,c,d,e,f,i,m,p){var q=nd(a,b);q||(q={},a.get(fb)[k](q));q.id_=b;q.affiliation_=c;q.total_=d;q.tax_=e;q.shipping_=f;q.city_=i;q.state_=m;q.country_=p;q.items_=q.items_||[];return q},pd=function(a,b,c,d,e,f,i){var a=nd(a,b)||od(a,b,"",0,0,0,"","",""),m;a:{if(a&&a.items_){m=a.items_;for(var p=0;p=a.b(bc,0))return!1;var c=sd();c==g&&(c=td());if(c==g||c==Infinity||isNaN(c))return!1;c>0?b(ud(c)):ra(U,"load",function(){vd(a,b)},!1);return!0},ud=function(a){var b=new Nc,c=j.min(j.floor(a/100),5E3);b.e(14,1,c>0?c+"00":"0");b.j(14,1,a);return b},sd=function(){var a=U.performance||U.webkitPerformance;return(a=a&&a.timing)&&a.loadEventStart-a.fetchStart},td=function(){if(U.top==U){var a=U.external,b=a&&a.onloadT;a&&!a.isValidLoadTime&&(b=g);b>2147483648&&(b=g); b>0&&a.setPageReadyTime();return b}};var R=function(a,b,c){function d(a){return function(b){if((b=b.get(dc)[a])&&b[s])for(var c=fc(e,a),d=0;d-1?(F(13),this.set(ib,a,!0)):typeof a==="object"&&a!==h&&this.oa(a);this.a.f("page")};C.u=function(a,b,c,d,e){if(a==""||!Lc(a)||b==""||!Lc(b))return!1;if(c!=g&&!Lc(c))return!1;if(d!=g&&!Mc(d))return!1;this.set(Tb,a,!0);this.set(Ub,b,!0);this.set(Vb,c,!0);this.set(Wb,d,!0);this.set(Sb,!!e,!0);this.a.f("event");return!0}; C.la=function(a,b,c,d){if(!a||!b)return!1;this.set(Xb,a,!0);this.set($b,b,!0);this.set(ac,c||I[w].href,!0);d&&this.set(ib,d,!0);this.a.f("social");return!0};C.ja=function(){var a=this;return vd(this.a,function(b){a.t(b)})};C.ma=function(){this.a.f("trans")};C.t=function(a){this.set(hb,a,!0);this.a.f("event")};C.S=function(a){this.l();var b=this;return{_trackEvent:function(c,d,e){F(91);b.u(a,c,d,e)}}};C.V=function(a){return this.get(a)}; C.da=function(a,b){if(a)if(a!=g&&(a.constructor+"")[n]("String")>-1)this.set(a,b);else if(typeof a=="object")for(var c in a)a.hasOwnProperty(c)&&this.set(c,a[c])};C.addEventListener=function(a,b){var c=this.get(dc)[a];c&&c[k](b)};C.removeEventListener=function(a,b){for(var c=this.get(dc)[a],d=0;c&&de.get(bb))a=!1;else if(!b||!c||E(b)[s]+E(c)[s]>64)a=!1;else{d!=1&&d!=2&&(d=3);var f={};ca(f,b);f.value=c;f.scope=d;e.get(N)[a]=f;a=!0}a&&this.a.i();return a};C.U=function(a){this.a.get(N)[a]=g;this.a.i()};C.Y=function(a){return(a=this.a.get(N)[a])&&a[ja]==1?a[ga]:g};C.ha=function(a,b,c){this.h().e(a,b,c)};C.ia=function(a,b,c){this.h().j(a,b,c)};C.Z=function(a,b){return this.h().getKey(a,b)}; C.$=function(a,b){return this.h().z(a,b)};C.P=function(a){this.h().v(a)};C.Q=function(a){this.h().w(a)};C.T=function(){return new Nc};C.H=function(a){a&&this.get(db)[k](a[B]())};C.M=function(){this.set(db,[])};C.I=function(a){a&&this.get(eb)[k](a[B]())};C.N=function(){this.set(eb,[])};C.K=function(a,b,c,d,e){if(a&&b){a=[a,b[B]()][A](":");if(d||e)a=[a,d,e][A](":");d=this.get(cb);d.splice(c?0:d[s],0,a)}};C.O=function(){this.set(cb,[])}; C.R=function(a){this.a[fa]();var b=this.get(M),c=kd(this.a);this.set(M,a);this.a.i();jd(this.a,c);this.set(M,b)};C.l=function(){this.a[fa]()};C.ga=function(a){a&&a!=""&&(this.set(tb,a),this.a.f("var"))};var wd=function(a){a.get(Qb)!=="trans"&&a.b(Cb,0)>=500&&a[v]();if(a.get(Qb)==="event"){var b=(new Date).getTime(),c=a.b(Db,0),d=a.b(yb,0),c=j.floor(0.2*((b-(c!=d?c:c*1E3))/1E3));c>0&&(a.set(Db,b),a.set(P,j.min(10,a.b(P,0)+c)));a.b(P,0)<=0&&a[v]()}},yd=function(a){a.get(Qb)==="event"&&a.set(P,j.max(0,a.b(P,10)-1))};var zd=function(){var a=[];this.add=function(b,c,d){d&&(c=E(""+c));a[k](b+"="+c)};this.toString=function(){return a[A]("&")}},Ad=function(a,b){(b||a.get(ab)!=2)&&a.m(Cb)},Bd=function(a,b){b.add("utmwv","5.1.7");b.add("utms",a.get(Cb));b.add("utmn",pa());var c=I[w].hostname;D(c)||b.add("utmhn",c,!0);c=a.get(Za);c!=100&&b.add("utmsp",c,!0)},Dd=function(a,b){b.add("utmac",a.get(Ca));a.get(Sb)&&b.add("utmni",1);Cd(a,b);J.p&&b.add("aip",1);b.add("utmu",Dc.ya())},Cd=function(a,b){function c(a,b){b&&d[k](a+ "="+b+";")}var d=[];c("__utma",pc(a));c("__utmz",vc(a,!1));c("__utmv",sc(a,!0));c("__utmx",kd(a));b.add("utmcc",d[A]("+"),!0)},Ed=function(a,b){a.get(Na)&&(b.add("utmcs",a.get(rb),!0),b.add("utmsr",a.get(mb)),b.add("utmsc",a.get(nb)),b.add("utmul",a.get(qb)),b.add("utmje",a.get(ob)),b.add("utmfl",a.get(pb),!0))},Fd=function(a,b){a.get(Qa)&&a.get(jb)&&b.add("utmdt",a.get(jb),!0);b.add("utmhid",a.get(lb));b.add("utmr",ya(a.get(kb),a.get(M)),!0);b.add("utmp",E(a.get(ib),!0),!0)},Gd=function(a,b){for(var c= a.get(gb),d=a.get(hb),e=a.get(N)||[],f=0;f=0&&![].reduce)throw new Md(a[s]);Od(a,b)||Pd(a,b)}else throw new Ld(a[s]);},Nd=function(a,b,c){var c=c||Kd+"/__utm.gif?",d=new Image(1,1);d.src=c+a;d.onload=function(){d.onload=h; b()}},Od=function(a,b){var c,d=Kd+"/p/__utm.gif",e=U.XDomainRequest;if(e)c=new e,c.open("POST",d);else if(e=U.XMLHttpRequest)e=new e,"withCredentials"in e&&(c=e,c.open("POST",d,!0),c.setRequestHeader("Content-Type","text/plain"));if(c)return c.onreadystatechange=function(){c.readyState==4&&(b(),c=h)},c.send(a),!0},Pd=function(a,b){if(I.body){a=aa(a);try{var c=I.createElement('')}catch(d){c=I.createElement("iframe"),ca(c,a)}c.height="0";c.width="0";c.style.display="none"; c.style.visibility="hidden";var e=I[w],e=Kd+"/u/post_iframe.html#"+aa(e.protocol+"//"+e[ia]+"/favicon.ico"),f=function(){c.src="";c.parentNode&&c.parentNode.removeChild(c)};ra(U,"beforeunload",f);var i=!1,m=0,p=function(){if(!i){try{if(m>9||c.contentWindow[w][ia]==I[w][ia]){i=!0;f();sa(U,"beforeunload",f);b();return}}catch(a){}m++;setTimeout(p,200)}};ra(c,"load",p);I.body.appendChild(c);c.src=e}else Ec(function(){Pd(a,b)},100)};var $=function(){this.p=!1;this.A={};this.B=[];this.ra=0;this._gasoCPath=this._gasoDomain=g;Q($[t],"_createTracker",$[t].k,55);Q($[t],"_getTracker",$[t].ta,0);Q($[t],"_getTrackerByName",$[t].o,51);Q($[t],"_getTrackers",$[t].ua,130);Q($[t],"_anonymizeIp",$[t].sa,16);ec()};C=$[t];C.ta=function(a,b){return this.k(a,g,b)};C.k=function(a,b,c){b&&F(23);c&&F(67);b==g&&(b="~"+J.ra++);a=new R(b,a,c);J.A[b]=a;J.B[k](a);return a};C.o=function(a){a=a||"";return J.A[a]||J.k(g,a)};C.ua=function(){return J.B[da](0)}; C.sa=function(){this.p=!0};var Qd=function(a){if(I.webkitVisibilityState=="prerender")return!1;a();return!0};var J=new $;var Rd=U._gat;Rd&&typeof Rd._getTracker=="function"?J=Rd:U._gat=J;var Kc=new X;(function(a){if(!Qd(a)){F(123);var b=!1,c=function(){!b&&Qd(a)&&(F(124),b=!0,sa(I,"webkitvisibilitychange",c))};ra(I,"webkitvisibilitychange",c)}})(function(){var a=U._gaq,b=!1;if(a&&typeof a[k]=="function"&&(b=Object[t][r].call(Object(a))=="[object Array]",!b)){Kc=a;return}U._gaq=Kc;b&&Kc[k].apply(Kc,a)});})(); _text/javascriptObplist00noX$versionX$objectsY$archiverT$top""()0!12NOPQRSTUVWXYZ[\]^_`abcdhiU$null  !R$6S$10R$2R$7R$3S$11R$8V$classR$4R$9R$0R$5R$1 !#$%&[NS.relativeWNS.base_&https://ssl.google-analytics.com/ga.js*+,-Z$classnameX$classesUNSURL./UNSURLXNSObject#AD:Y3456BWNS.keysZNS.objects789:;<=>?@A CDEFGHIJKLMVServer]Cache-Control\Content-TypeWExpires]Last-ModifiedTDate^Content-Length_Content-Encoding_X-Content-Type-OptionsTVarySAgeWGFE/2.0_max-age=7200, public_text/javascript_Tue, 11 Oct 2011 18:03:46 GMT_Tue, 20 Sep 2011 20:00:43 GMT_Tue, 11 Oct 2011 16:03:46 GMTU12570TgzipWnosniff_Accept-EncodingT4458*+ef_NSMutableDictionaryeg/\NSDictionary{*+jk_NSHTTPURLResponselm/_NSHTTPURLResponse]NSURLResponse_NSKeyedArchiverpq_WebResourceResponse#-27\b} %+.4=FHOWbdprtvxz|~ %)1HZz,0DRdg}r_&https://ssl.google-analytics.com/ga.jsծ_WebResourceFrameName_WebResourceTextEncodingNamePUUTF-8O9^ Snowsports - Taster at Milton Keynes Snowdome - Snowsports - Imperial College Union

Skip navigation

You are not logged in

Snowsports - Taster at Milton Keynes Snowdome

This includes coach travel there and back, 2 hrs recreational skiing/snowboarding (hire is FREE if you need it) and a drink at the bar afterwards.

The lessons option gives you 1 hour beginner lesson in ski or board.

Date: October 19th
Departing from London: 3pm
Getting back: around 11pm

Start:  Wednesday 19 Oct 2011 3:00 PM
End:  Wednesday 19 Oct 2011 11:15 PM

You must before you can purchase this item.

Ytext/html_jhttps://www.imperialcollegeunion.org/ski-243/snowsports-taster-at-milton-keynes-snowdome-3198/product.html 1U^p"Z#$ $)r){. .R.[FFK1KxK-6a|)2Sn"  v   \ w.7 $#Q##$x$()J)S__.cccjmjwnoo&p:pUtu u%mv`PY>V>qCCgCpDs| A A F G G I d ג \_ \z a a a   % . Mt M R R R ( \ e   ( C v ; )Ytnw % (C !5!>;M=>Dۦ۰